Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add pigeon #1712

Merged
merged 29 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ec2532a
add pigeon sounds
evemartin Aug 27, 2024
507c927
add pigeon sound and image
evemartin Aug 29, 2024
ecab511
Merge branch 'master' into add-pigeon
evemartin Aug 29, 2024
74aefad
switch between animals on theme switch, rotate pigeon
evemartin Aug 30, 2024
692aa08
update pigeon sound and cow group type
evemartin Aug 30, 2024
aca8050
write pigeon test, address pigeon edge case
evemartin Aug 30, 2024
ab7973f
change descriptions to be more general
evemartin Aug 30, 2024
fbc314c
modify test slightly
evemartin Aug 30, 2024
59f7e08
add line to test that I forgot
evemartin Aug 30, 2024
f8e7f1e
add line to test to wait for element
evemartin Aug 30, 2024
25c3c0f
use xpath instead of css_selector
evemartin Aug 30, 2024
b0d8eef
get rid of unnecessary check
evemartin Aug 30, 2024
c0498c6
fix typo
evemartin Aug 30, 2024
70dc1e1
test out adding delay to test
evemartin Aug 30, 2024
8f710f8
check that cow is there
evemartin Aug 30, 2024
5e3b42c
fix typo
evemartin Aug 30, 2024
3ca336a
test the test
evemartin Aug 30, 2024
327a27e
test if xpath works at all in this case
evemartin Aug 30, 2024
b856333
switch back to using css_selector
evemartin Aug 30, 2024
442e621
Merge branch 'master' into add-pigeon
evemartin Aug 30, 2024
938e26f
test out a small change to the test
evemartin Aug 30, 2024
9d5e90b
undo small change, run black
evemartin Aug 30, 2024
21663b4
Merge branch 'master' into add-pigeon
faucomte97 Sep 2, 2024
aa55222
Install latest portal
faucomte97 Sep 2, 2024
f2231c9
address PR comments - dynamically change cows block
evemartin Sep 3, 2024
87b4259
continue work on dynamic pigeon block
evemartin Sep 3, 2024
b75bea7
make pigeon block dynamic
evemartin Sep 3, 2024
e7324b7
tidy up, add pigeon translations
evemartin Sep 3, 2024
65732f4
Merge branch 'master' into add-pigeon
evemartin Sep 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
637 changes: 627 additions & 10 deletions Pipfile.lock

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions game/end_to_end_tests/test_level_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,30 @@ def test_electric_fuel_gauge(self):
)
electric_fuel_gauge = self.selenium.find_element(By.ID, "electricFuelGauge")
assert "visibility: visible" in electric_fuel_gauge.get_attribute("style")

def test_pigeon(self):
"""Test that cows on the map automatically become pigeons when the theme is changed to "city" """
page = self.go_to_level_editor()
page.go_to_scenery_tab()

source_cow = self.selenium.find_element(By.ID, "cow")
end_space = self.selenium.find_element(
By.CSS_SELECTOR, "rect[x='130'][y='530']"
)
ActionChains(self.selenium).drag_and_drop(source_cow, end_space).perform()

scenery_cow = self.selenium.find_elements(
By.CSS_SELECTOR, "image[x='0'][y='0']"
)
cow_link = scenery_cow[0].get_attribute("href")
assert cow_link == "/static/game/raphael_image/Clarice.svg"

Select(self.selenium.find_element(By.ID, "theme_select")).select_by_value(
"city"
)

scenery_pigeon = self.selenium.find_elements(
By.CSS_SELECTOR, "image[x='0'][y='0']"
)
pigeon_link = scenery_pigeon[0].get_attribute("href")
assert pigeon_link == "/static/game/raphael_image/pigeon.svg"
684 changes: 684 additions & 0 deletions game/static/game/image/pigeon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions game/static/game/js/blockly/msg/js/ca.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ Blockly.Msg["TRAFFIC_LIGHT_GREEN_TITLE"] = "semàfor verd";
Blockly.Msg["DEAD_END_TITLE"] = "és carrer sense sortida";
Blockly.Msg["AT_DESTINATION_TITLE"] = "a destí";
Blockly.Msg["COW_CROSSING_TITLE"] = "vaques";
Blockly.Msg["PIGEON_CROSSING_TITLE"] = "coloms";

Blockly.Msg["CALL_PROC_TITLE"] = "Crida";
Blockly.Msg["CALL_PROC_TOOLTIP"] = "Crida un procediment";
Expand Down
1 change: 1 addition & 0 deletions game/static/game/js/blockly/msg/js/en-gb.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ Blockly.Msg["TRAFFIC_LIGHT_GREEN_TITLE"] = "traffic light green";
Blockly.Msg["DEAD_END_TITLE"] = "is dead end";
Blockly.Msg["AT_DESTINATION_TITLE"] = "at destination";
Blockly.Msg["COW_CROSSING_TITLE"] = "cows";
Blockly.Msg["PIGEON_CROSSING_TITLE"] = "pigeons";

Blockly.Msg["CALL_PROC_TITLE"] = "Call";
Blockly.Msg["CALL_PROC_TOOLTIP"] = "Calls a procedure";
Expand Down
1 change: 1 addition & 0 deletions game/static/game/js/blockly/msg/js/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ Blockly.Msg["TRAFFIC_LIGHT_GREEN_TITLE"] = "traffic light green";
Blockly.Msg["DEAD_END_TITLE"] = "is dead end";
Blockly.Msg["AT_DESTINATION_TITLE"] = "at destination";
Blockly.Msg["COW_CROSSING_TITLE"] = "cows";
Blockly.Msg["PIGEON_CROSSING_TITLE"] = "pigeons";

Blockly.Msg["CALL_PROC_TITLE"] = "Call";
Blockly.Msg["CALL_PROC_TOOLTIP"] = "Calls a procedure";
Expand Down
1 change: 1 addition & 0 deletions game/static/game/js/blockly/msg/js/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ Blockly.Msg["TRAFFIC_LIGHT_GREEN_TITLE"] = "semáforo en verde";
Blockly.Msg["DEAD_END_TITLE"] = "es un callejón sin salida";
Blockly.Msg["AT_DESTINATION_TITLE"] = "en destino";
Blockly.Msg["COW_CROSSING_TITLE"] = "vacas";
Blockly.Msg["PIGEON_CROSSING_TITLE"] = "palomas";

Blockly.Msg["CALL_PROC_TITLE"] = "Llamar";
Blockly.Msg["CALL_PROC_TOOLTIP"] = "Llamar a una función";
Expand Down
1 change: 1 addition & 0 deletions game/static/game/js/blockly/msg/js/fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ Blockly.Msg["TRAFFIC_LIGHT_GREEN_TITLE"] = "feu vert";
Blockly.Msg["DEAD_END_TITLE"] = "cul-de-sac";
Blockly.Msg["AT_DESTINATION_TITLE"] = "arrivé à destination";
Blockly.Msg["COW_CROSSING_TITLE"] = "vaches";
Blockly.Msg["PIGEON_CROSSING_TITLE"] = "pigeons";

Blockly.Msg["CALL_PROC_TITLE"] = "Appeler";
Blockly.Msg["CALL_PROC_TOOLTIP"] = "Appeler une fonction";
Expand Down
1 change: 1 addition & 0 deletions game/static/game/js/blockly/msg/js/hi.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ Blockly.Msg["TRAFFIC_LIGHT_GREEN_TITLE"] = "ट्रैफिक लाइट
Blockly.Msg["DEAD_END_TITLE"] = "आगे का रास्ता बंद है";
Blockly.Msg["AT_DESTINATION_TITLE"] = "मंजिल /गंतव्य पर";
Blockly.Msg["COW_CROSSING_TITLE"] = "गायों";
Blockly.Msg["PIGEON_CROSSING_TITLE"] = "कबूतरों";

Blockly.Msg["CALL_PROC_TITLE"] = "पुकारना";
Blockly.Msg["CALL_PROC_TOOLTIP"] = "एक प्रक्रिया बुलाना";
Expand Down
17 changes: 15 additions & 2 deletions game/static/game/js/blocklyCustomBlocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,26 @@ function initCustomBlocksDescription() {
init: function() {
this.setColour(210);
this.setOutput(true, 'Boolean');
let imageUrl = ocargo.Drawing.animalType == ocargo.Cow.PIGEON ? ocargo.Drawing.pigeonUrl : ocargo.Drawing.whiteCowUrl
this.appendDummyInput()
.appendField(Blockly.Msg.COW_CROSSING_TITLE)
.appendField(new Blockly.FieldImage(ocargo.Drawing.imageDir + ocargo.Drawing.whiteCowUrl,
.appendField(ocargo.Drawing.animalType == ocargo.Cow.PIGEON ? Blockly.Msg.PIGEON_CROSSING_TITLE: Blockly.Msg.COW_CROSSING_TITLE)
.appendField(new Blockly.FieldImage(ocargo.Drawing.imageDir + imageUrl,
ocargo.BlocklyControl.COW_WIDTH,
ocargo.BlocklyControl.BLOCK_HEIGHT), 'IMAGE');
}
};

Blockly.Blocks['pigeon_crossing_IMAGE_ONLY'] = {
init: function() {
this.setColour(210);
this.setOutput(true, 'Boolean');
this.appendDummyInput()
.appendField("pigeons")
.appendField(new Blockly.FieldImage(ocargo.Drawing.imageDir + ocargo.Drawing.pigeonUrl,
ocargo.BlocklyControl.COW_WIDTH,
ocargo.BlocklyControl.BLOCK_HEIGHT), 'IMAGE');
}
}
/****************/
/* Procedures */
/****************/
Expand Down
7 changes: 4 additions & 3 deletions game/static/game/js/cow.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ ocargo.Cow.prototype.reset = function() {
ocargo.Cow.prototype.queueLeaveAnimation = function(model, node) {
ocargo.animation.appendAnimation({
type: 'callable',
functionCall: ocargo.sound.cow,
description: 'cow sound'
functionCall: this.type == ocargo.Cow.PIGEON ? ocargo.sound.pigeon : ocargo.sound.cow,
description: 'animal sound'
});
ocargo.animation.appendAnimation({
type: 'cow_leave',
id: this.id,
coordinate: node.coordinate,
description: 'Cow leaving'
description: 'animal leaving'
});
};

Expand All @@ -49,3 +49,4 @@ ocargo.Cow.ACTIVE = 'ACTIVE';
ocargo.Cow.INACTIVE = 'INACTIVE';
ocargo.Cow.WHITE = 'WHITE';
ocargo.Cow.BROWN = 'BROWN';
ocargo.Cow.PIGEON = 'PIGEON';
6 changes: 6 additions & 0 deletions game/static/game/js/drawing.js
Original file line number Diff line number Diff line change
Expand Up @@ -1236,11 +1236,14 @@ ocargo.Drawing.renderCoins = function (coins) {
}

ocargo.Drawing.cowUrl = function (type) {
ocargo.Drawing.animalType = type;
switch (type) {
case ocargo.Cow.WHITE:
return ocargo.Drawing.whiteCowUrl
case ocargo.Cow.BROWN:
return ocargo.Drawing.brownCowUrl
case ocargo.Cow.PIGEON:
return ocargo.Drawing.pigeonUrl
default:
return ocargo.Drawing.whiteCowUrl
}
Expand Down Expand Up @@ -1284,6 +1287,9 @@ ocargo.Drawing.TOP_VIEW = 'top_view'

ocargo.Drawing.whiteCowUrl = 'Clarice.svg'
ocargo.Drawing.brownCowUrl = 'Clarice_Jersey.svg'
ocargo.Drawing.pigeonUrl = 'pigeon.svg'

ocargo.Drawing.imageDir = '/static/game/image/'
ocargo.Drawing.raphaelImageDir = '/static/game/raphael_image/'

ocargo.Drawing.animalType = 'WHITE'
120 changes: 89 additions & 31 deletions game/static/game/js/level_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,8 @@ ocargo.LevelEditor = function(levelId) {

for (var i = 0; i < BLOCKS.length; i++) {
var type = BLOCKS[i];
var block = Blockly.mainWorkspace.newBlock(type);
let usePigeons = type === "cow_crossing" && currentTheme == THEMES.city
var block = usePigeons ? Blockly.mainWorkspace.newBlock("pigeon_crossing_IMAGE_ONLY") : Blockly.mainWorkspace.newBlock(type);
block.initSvg();
block.render();

Expand Down Expand Up @@ -909,7 +910,7 @@ ocargo.LevelEditor = function(levelId) {
var color = COW_GROUP_COLOR_PALETTE[(currentCowGroupId - 1) % COW_GROUP_COLOR_PALETTE.length];
var style = 'background-color: ' + color;
var value = 'group' + currentCowGroupId++;
var type = ocargo.Cow.WHITE;
var type = currentTheme == THEMES.city ? ocargo.Cow.PIGEON : ocargo.Cow.WHITE;

cowGroups[value] = {
id: value,
Expand Down Expand Up @@ -2374,6 +2375,7 @@ ocargo.LevelEditor = function(levelId) {

function setTheme(theme) {
currentTheme = theme;
let newType = currentTheme == THEMES.city ? ocargo.Cow.PIGEON : ocargo.Cow.WHITE;

for (var x = 0; x < GRID_WIDTH; x++) {
for (var y = 0; y < GRID_HEIGHT; y++) {
Expand All @@ -2397,6 +2399,36 @@ ocargo.LevelEditor = function(levelId) {
});

$('#paper').css({'background-color': theme.background});

const animalSource = theme == THEMES.city ? "/static/game/image/pigeon.svg" : "/static/game/image/Clarice.svg";

$('#cow').each(function(index, element) {
element.src = animalSource;
})

$('#animals_label').each(function(index, element) {
element.innerHTML = theme == THEMES.city ? "Pigeons" : "Cows";
})

for (let [key, value] of Object.entries(cowGroups)) {
value["type"] = theme == THEMES.city ? ocargo.Cow.PIGEON : ocargo.Cow.WHITE;
}

for (let i = 0; i < cows.length; i++) {
cows[i].updateTheme();
}

const pigeonHTML = `<svg class="block_image"><g transform="translate(10,0)" <path="" class="blocklyPathDark" fill="#496684" d="m 0,0 H 111.34375 v 30 H 0 V 20 c 0,-10 -8,8 -8,-7.5 s 8,2.5 8,-7.5 z
"><path class="blocklyPath" stroke="none" fill="#5b80a5" d="m 0,0 H 111.34375 v 30 H 0 V 20 c 0,-10 -8,8 -8,-7.5 s 8,2.5 8,-7.5 z
"></path><path class="blocklyPathLight" stroke="#8ca6c0" d="m 0.5,0.5 H 110.84375 M 110.84375,0.5 M 0.5,29.5 V 18.5 m -7.36,-0.5 q -1.52,-5.5 0,-11 m 7.36,1 V 0.5 H 1
"></path><text class="blocklyText" y="12.5" transform="translate(10,5)">pigeons</text><g transform="translate(71.34375,5)"><image height="20px" width="30px" xlink:href="/static/game/image/pigeon.svg" alt=""></image></g></g></svg>`;

const cowHTML = `<svg class="block_image"><g transform="translate(10,0)" <path="" class="blocklyPathDark" fill="#496684" d="m 0,0 H 93.40625 v 30 H 0 V 20 c 0,-10 -8,8 -8,-7.5 s 8,2.5 8,-7.5 z
"><path class="blocklyPath" stroke="none" fill="#5b80a5" d="m 0,0 H 93.40625 v 30 H 0 V 20 c 0,-10 -8,8 -8,-7.5 s 8,2.5 8,-7.5 z
"></path><path class="blocklyPathLight" stroke="#8ca6c0" d="m 0.5,0.5 H 92.90625 M 92.90625,0.5 M 0.5,29.5 V 18.5 m -7.36,-0.5 q -1.52,-5.5 0,-11 m 7.36,1 V 0.5 H 1
"></path><text class="blocklyText" y="12.5" transform="translate(10,5)">cows</text><g transform="translate(53.40625,5)"><image height="20px" width="30px" xlink:href="/static/game/image/Clarice.svg" alt=""></image></g></g></svg>`;

$("#cow_crossing_image").html(newType == ocargo.Cow.PIGEON ? pigeonHTML : cowHTML);
}

function sortNodes(nodes) {
Expand Down Expand Up @@ -2554,35 +2586,6 @@ ocargo.LevelEditor = function(levelId) {
new InternalTrafficLight(trafficLightData[i]);
}

if(COW_LEVELS_ENABLED) {
var cowGroupData = JSON.parse(state.cows);
for (var i = 0; i < cowGroupData.length; i++) {
// Add new group to group select element
if (i >= Object.keys(cowGroups).length) {
addCowGroup();
}
var cowGroupId = Object.keys(cowGroups)[i];
cowGroups[cowGroupId].minCows = cowGroupData[i].minCows;
cowGroups[cowGroupId].maxCows = cowGroupData[i].maxCows;
cowGroups[cowGroupId].type = cowGroupData[i].type;

if (cowGroupData[i].potentialCoordinates != null) {
for (var j = 0; j < cowGroupData[i].potentialCoordinates.length; j++) {
var cowData = {
coordinates: [cowGroupData[i].potentialCoordinates[j]],
group: cowGroups[cowGroupId]
};
new InternalCow(cowData);
}
}
}

// Trigger change listener on cow group select box to set initial min/max values
$('#cow_group_select').change();

markCowNodes();
}

// Load in destination and origin nodes
if (state.destinations) {
var houses = JSON.parse(state.destinations);
Expand Down Expand Up @@ -2630,6 +2633,36 @@ ocargo.LevelEditor = function(levelId) {
PAPER_HEIGHT - currentTheme.decor[decor[i].decorName].height - decor[i].y + PAPER_PADDING);
}

//Load in cow data
if(COW_LEVELS_ENABLED) {
var cowGroupData = JSON.parse(state.cows);
for (var i = 0; i < cowGroupData.length; i++) {
// Add new group to group select element
if (i >= Object.keys(cowGroups).length) {
addCowGroup();
}
var cowGroupId = Object.keys(cowGroups)[i];
cowGroups[cowGroupId].minCows = cowGroupData[i].minCows;
cowGroups[cowGroupId].maxCows = cowGroupData[i].maxCows;
cowGroups[cowGroupId].type = cowGroupData[i].type;

if (cowGroupData[i].potentialCoordinates != null) {
for (var j = 0; j < cowGroupData[i].potentialCoordinates.length; j++) {
var cowData = {
coordinates: [cowGroupData[i].potentialCoordinates[j]],
group: cowGroups[cowGroupId]
};
new InternalCow(cowData);
}
}
}

// Trigger change listener on cow group select box to set initial min/max values
$('#cow_group_select').change();

markCowNodes();
}

// Load in block data
if(state.blocks) {
for(var i = 0; i < BLOCKS.length; i++) {
Expand Down Expand Up @@ -2918,6 +2951,31 @@ ocargo.LevelEditor = function(levelId) {

};

this.updateTheme = function() {
let newType = currentTheme == THEMES.city ? ocargo.Cow.PIGEON : ocargo.Cow.WHITE;
let transformDimensions = this["image"]["_"]["transform"][0]
let rotateDimensions = this["image"]["_"]["transform"][1]
let x = transformDimensions[1]
let y = transformDimensions[2]
let r = 0;
if (rotateDimensions) {
r = rotateDimensions[1];
}

this.image.remove();

this.image = drawing.createCowImage(newType);
if (this.controlledNode !== null) {
let controlledNode = this.controlledNode;
let coordinates = controlledNode.coordinate;
drawing.setCowImagePosition(coordinates, this.image, controlledNode);
} else {
this.image.transform("t" + x + "," + y + " r" + r);
}

setupCowListeners(this);
}

this.image = drawing.createCowImage(data.group.type);
this.valid = false;

Expand Down
8 changes: 8 additions & 0 deletions game/static/game/js/sound.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ ocargo.sound.cowSound = new Howl({
urls: ['/static/game/sound/cow.mp3', '/static/game/sound/cow.ogg']
});

ocargo.sound.pigeonSound = new Howl({
urls: ['/static/game/sound/pigeon.mp3', '/static/game/sound/pigeon.ogg']
});

function safePlay(sound) {
try {
sound.play();
Expand Down Expand Up @@ -96,6 +100,10 @@ ocargo.sound.cow = function() {
safePlay(ocargo.sound.cowSound);
};

ocargo.sound.pigeon = function() {
safePlay(ocargo.sound.pigeonSound);
}

ocargo.sound.sound_horn = function() {
safePlay(ocargo.sound.hornSound);
};
Expand Down
Loading