rapid-router 5.18.0__py2.py3-none-any.whl → 7.6.8__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- example_project/rapid_router_test_settings.py +19 -7
- example_project/settings.py +21 -8
- example_project/urls.py +5 -6
- game/__init__.py +1 -1
- game/admin.py +7 -2
- game/character.py +8 -0
- game/decor.py +40 -0
- game/end_to_end_tests/base_game_test.py +34 -27
- game/end_to_end_tests/editor_page.py +15 -0
- game/end_to_end_tests/game_page.py +88 -20
- game/end_to_end_tests/selenium_test_case.py +1 -20
- game/end_to_end_tests/test_cow_crashes.py +3 -5
- game/end_to_end_tests/test_level_editor.py +273 -10
- game/end_to_end_tests/test_level_selection.py +25 -3
- game/end_to_end_tests/test_play_through.py +222 -127
- game/end_to_end_tests/test_python_levels.py +41 -7
- game/end_to_end_tests/test_saving_workspace.py +2 -1
- game/forms.py +7 -1
- game/level_management.py +26 -11
- game/messages.py +899 -337
- game/migrations/0001_squashed_0025_levels_ordering_pt1.py +19 -1
- game/migrations/0026_levels_pt2.py +13 -2
- game/migrations/0032_cannot_turn_left_level.py +13 -2
- game/migrations/0033_recursion_level.py +13 -2
- game/migrations/0034_joes_level.py +13 -2
- game/migrations/0035_disable_route_score_level_70.py +0 -2
- game/migrations/0036_level_score_73.py +0 -2
- game/migrations/0037_level_score_79.py +0 -2
- game/migrations/0038_level_score_40.py +0 -1
- game/migrations/0042_level_score_73.py +0 -2
- game/migrations/0048_add_cow_field_and_blocks.py +0 -2
- game/migrations/0049_level_score_34.py +0 -2
- game/migrations/0050_level_score_40.py +0 -2
- game/migrations/0051_level_score_49.py +0 -1
- game/migrations/0086_loop_levels.py +13 -2
- game/migrations/0092_disable_algo_score_in_custom_levels.py +28 -0
- game/migrations/0093_alter_level_character_name.py +18 -0
- game/migrations/0094_add_hint_lesson_subtitle_to_levels.py +28 -0
- game/migrations/0095_level_commands.py +18 -0
- game/migrations/0096_alter_level_commands.py +18 -0
- game/migrations/0097_add_python_den_levels.py +1515 -0
- game/migrations/0098_add_episode_link_fields.py +44 -0
- game/migrations/0099_python_episodes_links.py +103 -0
- game/migrations/0100_reorder_python_levels.py +179 -0
- game/migrations/0101_rename_episodes.py +45 -0
- game/migrations/0102_reoder_episodes_13_14.py +136 -0
- game/migrations/0103_level_1015_solution.py +26 -0
- game/migrations/0104_remove_level_direct_drive.py +17 -0
- game/migrations/0105_delete_invalid_attempts.py +18 -0
- game/migrations/0106_fields_to_snake_case.py +48 -0
- game/migrations/0107_rename_worksheet_link_episode_student_worksheet_link.py +18 -0
- game/migrations/0108_episode_indy_worksheet_link.py +18 -0
- game/migrations/0109_create_episodes_23_and_24.py +99 -0
- game/migrations/0110_remove_episode_indy_worksheet_link_and_more.py +100 -0
- game/migrations/0111_create_worksheets.py +149 -0
- game/migrations/0112_worksheet_locked_classes.py +21 -0
- game/migrations/0113_level_needs_approval.py +18 -0
- game/migrations/0114_default_and_non_student_levels_no_approval.py +31 -0
- game/migrations/0115_level_level__default_does_not_need_approval.py +22 -0
- game/migrations/0116_update_worksheet_video_links.py +68 -0
- game/migrations/0117_update_solutions_to_if_else.py +61 -0
- game/models.py +127 -17
- game/permissions.py +51 -19
- game/python_den_urls.py +26 -0
- game/random_road.py +9 -9
- game/serializers.py +12 -17
- game/static/django_reverse_js/js/reverse.js +171 -0
- game/static/game/css/LilitaOne-Regular.ttf +0 -0
- game/static/game/css/backgrounds.css +8 -12
- game/static/game/css/dataTables.custom.css +3 -2
- game/static/game/css/editor.css +47 -0
- game/static/game/css/game.css +37 -43
- game/static/game/css/game_screen.css +16 -0
- game/static/game/css/level_editor.css +5 -0
- game/static/game/css/level_selection.css +17 -2
- game/static/game/image/Python_Den_hero_student.png +0 -0
- game/static/game/image/Python_levels_page.svg +1954 -0
- game/static/game/image/characters/front_view/Electric_van.svg +448 -0
- game/static/game/image/characters/top_view/Electric_van.svg +448 -0
- game/static/game/image/decor/city/solar_panel.svg +1200 -0
- game/static/game/image/decor/farm/solar_panel.svg +86 -0
- game/static/game/image/decor/grass/solar_panel.svg +86 -0
- game/static/game/image/decor/snow/solar_panel.svg +173 -0
- game/static/game/image/electric_van.svg +448 -0
- game/static/game/image/icons/description.svg +1 -0
- game/static/game/image/icons/hint.svg +1 -0
- game/static/game/image/icons/python.svg +1 -1
- game/static/game/image/pigeon.svg +684 -0
- game/static/game/image/python_den_header.svg +19 -0
- game/static/game/js/animation.js +65 -24
- game/static/game/js/blockly/msg/js/bg.js +52 -1
- game/static/game/js/blockly/msg/js/ca.js +52 -1
- game/static/game/js/blockly/msg/js/en-gb.js +2 -0
- game/static/game/js/blockly/msg/js/en.js +2 -0
- game/static/game/js/blockly/msg/js/es.js +52 -1
- game/static/game/js/blockly/msg/js/fr.js +2 -0
- game/static/game/js/blockly/msg/js/hi.js +2 -0
- game/static/game/js/blockly/msg/js/it.js +52 -1
- game/static/game/js/blockly/msg/js/pl.js +52 -1
- game/static/game/js/blockly/msg/js/pt-br.js +52 -1
- game/static/game/js/blockly/msg/js/ru.js +52 -1
- game/static/game/js/blockly/msg/js/ur.js +52 -1
- game/static/game/js/blocklyCustomBlocks.js +93 -52
- game/static/game/js/button.js +12 -0
- game/static/game/js/cow.js +11 -7
- game/static/game/js/drawing.js +68 -29
- game/static/game/js/editor.js +23 -0
- game/static/game/js/game.js +74 -110
- game/static/game/js/level_editor.js +646 -274
- game/static/game/js/level_moderation.js +33 -2
- game/static/game/js/level_selection.js +1 -1
- game/static/game/js/loadLanguages.js +2 -2
- game/static/game/js/model.js +32 -2
- game/static/game/js/pythonControl.js +14 -1
- game/static/game/js/scoreboard.js +0 -37
- game/static/game/js/scoreboardSharedLevels.js +48 -0
- game/static/game/js/skulpt/skulpt-stdlib.js +1 -1
- game/static/game/js/sound.js +52 -5
- game/static/game/raphael_image/characters/top_view/Electric_van.svg +448 -0
- game/static/game/raphael_image/decor/city/solar_panel.svg +1200 -0
- game/static/game/raphael_image/decor/farm/solar_panel.svg +86 -0
- game/static/game/raphael_image/decor/grass/solar_panel.svg +86 -0
- game/static/game/raphael_image/decor/snow/solar_panel.svg +173 -0
- game/static/game/raphael_image/pigeon.svg +685 -0
- game/static/game/sass/game.scss +2 -2
- game/static/game/sound/clown_horn.mp3 +0 -0
- game/static/game/sound/clown_horn.ogg +0 -0
- game/static/game/sound/electric_van_starting.mp3 +0 -0
- game/static/game/sound/electric_van_starting.ogg +0 -0
- game/static/game/sound/pigeon.mp3 +0 -0
- game/static/game/sound/pigeon.ogg +0 -0
- game/static/game/sound/sleigh_bells.mp3 +0 -0
- game/static/game/sound/sleigh_bells.ogg +0 -0
- game/static/game/sound/sleigh_crash.mp3 +0 -0
- game/static/game/sound/sleigh_crash.ogg +0 -0
- game/templates/game/base.html +34 -14
- game/templates/game/basenonav.html +11 -5
- game/templates/game/game.html +142 -38
- game/templates/game/level_editor.html +340 -236
- game/templates/game/level_moderation.html +19 -6
- game/templates/game/level_selection.html +18 -110
- game/templates/game/python_den_level_selection.html +291 -0
- game/templates/game/python_den_worksheet.html +101 -0
- game/templates/game/scoreboard.html +83 -64
- game/tests/test_level_editor.py +94 -26
- game/tests/test_level_selection.py +149 -46
- game/tests/test_python_den_worksheet.py +85 -0
- game/tests/test_scoreboard.py +34 -7
- game/tests/utils/level.py +32 -26
- game/theme.py +5 -5
- game/urls.py +199 -61
- game/views/language_code_conversions.py +86 -86
- game/views/level.py +155 -63
- game/views/level_editor.py +88 -55
- game/views/level_moderation.py +23 -0
- game/views/level_selection.py +116 -47
- game/views/level_solutions.py +491 -106
- game/views/scoreboard.py +76 -51
- game/views/worksheet.py +25 -0
- rapid_router-7.6.8.dist-info/METADATA +174 -0
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/RECORD +164 -104
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/WHEEL +1 -1
- example_project/manage.py +0 -10
- game/static/game/image/actions/go.svg +0 -18
- game/static/game/js/js-reverse.js +0 -14
- game/static/game/js/pqselect.min.js +0 -9
- game/static/game/js/widget-scroller.js +0 -906
- rapid_router-5.18.0.dist-info/METADATA +0 -17
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info/licenses}/LICENSE.md +0 -0
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/top_level.txt +0 -0
|
@@ -8,6 +8,8 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
8
8
|
/* Constants */
|
|
9
9
|
/*************/
|
|
10
10
|
|
|
11
|
+
const TAB_PANE_WIDTH = 500;
|
|
12
|
+
|
|
11
13
|
var LIGHT_RED_URL = ocargo.Drawing.raphaelImageDir + 'trafficLight_red.svg';
|
|
12
14
|
var LIGHT_GREEN_URL = ocargo.Drawing.raphaelImageDir + 'trafficLight_green.svg';
|
|
13
15
|
|
|
@@ -85,6 +87,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
85
87
|
var originNode = null;
|
|
86
88
|
var houseNodes = [];
|
|
87
89
|
var currentTheme = THEMES.grass;
|
|
90
|
+
var needsApproval = false;
|
|
88
91
|
|
|
89
92
|
// Reference to the Raphael elements for each square
|
|
90
93
|
var grid;
|
|
@@ -189,6 +192,8 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
189
192
|
tabs.character = new ocargo.Tab($('#character_radio'), $('#character_radio + label'), $('#character_pane'));
|
|
190
193
|
tabs.blocks = new ocargo.Tab($('#blocks_radio'), $('#blocks_radio + label'), $('#blocks_pane'));
|
|
191
194
|
tabs.random = new ocargo.Tab($('#random_radio'), $('#random_radio + label'), $('#random_pane'));
|
|
195
|
+
tabs.description = new ocargo.Tab($('#description_radio'), $('#description_radio + label'), $('#description_pane'));
|
|
196
|
+
tabs.hint = new ocargo.Tab($('#hint_radio'), $('#hint_radio + label'), $('#hint_pane'));
|
|
192
197
|
tabs.load = new ocargo.Tab($('#load_radio'), $('#load_radio + label'), $('#load_pane'));
|
|
193
198
|
tabs.save = new ocargo.Tab($('#save_radio'), $('#save_radio + label'), $('#save_pane'));
|
|
194
199
|
tabs.share = new ocargo.Tab($('#share_radio'), $('#share_radio + label'), $('#share_pane'));
|
|
@@ -202,6 +207,8 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
202
207
|
setupCharacterTab();
|
|
203
208
|
setupBlocksTab();
|
|
204
209
|
setupRandomTab();
|
|
210
|
+
setupDescriptionTab();
|
|
211
|
+
setupHintTab();
|
|
205
212
|
setupLoadTab();
|
|
206
213
|
setupSaveTab();
|
|
207
214
|
setupShareTab();
|
|
@@ -318,28 +325,25 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
318
325
|
}
|
|
319
326
|
});
|
|
320
327
|
|
|
321
|
-
$('.decor_button').
|
|
322
|
-
new InternalDecor(e.target.id);
|
|
323
|
-
});
|
|
328
|
+
$('.decor_button').mousedown(handleDraggableDecorMouseDown);
|
|
324
329
|
|
|
325
|
-
$('#trafficLightRed').
|
|
326
|
-
|
|
327
|
-
"startingState": ocargo.TrafficLight.RED,
|
|
328
|
-
"sourceCoordinate": null, "direction": null});
|
|
330
|
+
$('#trafficLightRed').mousedown(function(e) {
|
|
331
|
+
handleDraggableTrafficLightsMouseDown(e, ocargo.TrafficLight.RED);
|
|
329
332
|
});
|
|
330
333
|
|
|
331
|
-
$('#trafficLightGreen').
|
|
332
|
-
|
|
333
|
-
"startingState": ocargo.TrafficLight.GREEN,
|
|
334
|
-
"sourceCoordinate": null, "direction": null});
|
|
334
|
+
$('#trafficLightGreen').mousedown(function(e) {
|
|
335
|
+
handleDraggableTrafficLightsMouseDown(e, ocargo.TrafficLight.GREEN);
|
|
335
336
|
});
|
|
336
337
|
|
|
337
338
|
if(COW_LEVELS_ENABLED) {
|
|
338
339
|
if (Object.keys(cowGroups).length == 0) {
|
|
339
340
|
addCowGroup();
|
|
340
341
|
}
|
|
341
|
-
$('#cow').
|
|
342
|
-
|
|
342
|
+
$('#cow').mouseover(function(e) {
|
|
343
|
+
e.target.style.cursor = "pointer";
|
|
344
|
+
})
|
|
345
|
+
$('#cow').mousedown(function(e) {
|
|
346
|
+
handleDraggableCowMouseDown(e, "group1")
|
|
343
347
|
});
|
|
344
348
|
}
|
|
345
349
|
}
|
|
@@ -412,7 +416,8 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
412
416
|
|
|
413
417
|
for (var i = 0; i < BLOCKS.length; i++) {
|
|
414
418
|
var type = BLOCKS[i];
|
|
415
|
-
|
|
419
|
+
let usePigeons = type === "cow_crossing" && currentTheme == THEMES.city
|
|
420
|
+
var block = usePigeons ? Blockly.mainWorkspace.newBlock("pigeon_crossing_IMAGE_ONLY") : Blockly.mainWorkspace.newBlock(type);
|
|
416
421
|
block.initSvg();
|
|
417
422
|
block.render();
|
|
418
423
|
|
|
@@ -478,6 +483,18 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
478
483
|
});
|
|
479
484
|
}
|
|
480
485
|
|
|
486
|
+
function setupDescriptionTab() {
|
|
487
|
+
tabs.description.setOnChange(function() {
|
|
488
|
+
transitionTab(tabs.description);
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function setupHintTab() {
|
|
493
|
+
tabs.hint.setOnChange(function() {
|
|
494
|
+
transitionTab(tabs.hint);
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
481
498
|
function goToMapTab() {
|
|
482
499
|
tabs.map.select();
|
|
483
500
|
}
|
|
@@ -615,17 +632,27 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
615
632
|
return;
|
|
616
633
|
}
|
|
617
634
|
|
|
618
|
-
|
|
635
|
+
const nameInput = $('#levelNameInput')
|
|
636
|
+
const newName = nameInput.val();
|
|
619
637
|
if (!newName || newName === "") {
|
|
620
|
-
|
|
638
|
+
ocargo.Drawing.startPopup(
|
|
639
|
+
"Oh no!",
|
|
640
|
+
"No level title!",
|
|
641
|
+
"Sorry, you need to specify a title for your" +
|
|
642
|
+
" level to be saved.",
|
|
643
|
+
);
|
|
621
644
|
return;
|
|
622
645
|
}
|
|
623
646
|
|
|
624
|
-
|
|
625
|
-
|
|
647
|
+
const regex = /^[\w ]*$/;
|
|
648
|
+
const validString = regex.exec(nameInput.val());
|
|
626
649
|
if (!validString) {
|
|
627
|
-
ocargo.Drawing.startPopup(
|
|
628
|
-
|
|
650
|
+
ocargo.Drawing.startPopup(
|
|
651
|
+
"Oh no!",
|
|
652
|
+
"You used some invalid characters.",
|
|
653
|
+
"Try saving your level again using only" +
|
|
654
|
+
" letters and numbers."
|
|
655
|
+
);
|
|
629
656
|
return;
|
|
630
657
|
}
|
|
631
658
|
|
|
@@ -634,33 +661,37 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
634
661
|
}
|
|
635
662
|
|
|
636
663
|
// Test to see if we already have the level saved
|
|
637
|
-
|
|
638
|
-
|
|
664
|
+
const table = $("#saveLevelTable");
|
|
665
|
+
let existingId = -1;
|
|
639
666
|
|
|
640
|
-
for (
|
|
641
|
-
|
|
642
|
-
|
|
667
|
+
for (let i = 0; i < table[0].rows.length; i++) {
|
|
668
|
+
const row = table[0].rows[i];
|
|
669
|
+
const existingName = row.cells[0].innerHTML;
|
|
643
670
|
if (existingName === newName) {
|
|
644
671
|
existingId = row.getAttribute('value');
|
|
645
672
|
break;
|
|
646
673
|
}
|
|
647
674
|
}
|
|
648
675
|
|
|
649
|
-
if (existingId
|
|
676
|
+
if (existingId !== -1) {
|
|
650
677
|
if (!saveState.isCurrentLevel(existingId)) {
|
|
651
|
-
|
|
678
|
+
const onYes = function(){
|
|
652
679
|
saveLevelLocal(existingId);
|
|
653
680
|
$("#myModal").hide()
|
|
654
681
|
$("#ocargo-modal").hide()
|
|
655
682
|
};
|
|
656
|
-
|
|
683
|
+
const onNo = function(){
|
|
657
684
|
$("#myModal").hide()
|
|
658
685
|
$("#ocargo-modal").hide()
|
|
659
686
|
};
|
|
660
|
-
ocargo.Drawing.startYesNoPopup(
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}
|
|
687
|
+
ocargo.Drawing.startYesNoPopup(
|
|
688
|
+
"Overwriting",
|
|
689
|
+
"Warning",
|
|
690
|
+
`Level ${newName} already exists. Are
|
|
691
|
+
you sure you want to overwrite it?`,
|
|
692
|
+
onYes,
|
|
693
|
+
onNo
|
|
694
|
+
);
|
|
664
695
|
} else {
|
|
665
696
|
saveLevelLocal(existingId);
|
|
666
697
|
}
|
|
@@ -701,7 +732,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
701
732
|
}
|
|
702
733
|
|
|
703
734
|
function setupShareTab() {
|
|
704
|
-
//
|
|
735
|
+
// Set up the behaviour for when the tab is selected
|
|
705
736
|
tabs.share.setOnChange(function() {
|
|
706
737
|
if (!isIndependentStudent() || !isLoggedIn("share") || !canShare() || !isLevelOwned()) {
|
|
707
738
|
restorePreviousTab();
|
|
@@ -880,7 +911,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
880
911
|
var color = COW_GROUP_COLOR_PALETTE[(currentCowGroupId - 1) % COW_GROUP_COLOR_PALETTE.length];
|
|
881
912
|
var style = 'background-color: ' + color;
|
|
882
913
|
var value = 'group' + currentCowGroupId++;
|
|
883
|
-
var type = ocargo.Cow.WHITE;
|
|
914
|
+
var type = currentTheme == THEMES.city ? ocargo.Cow.PIGEON : ocargo.Cow.WHITE;
|
|
884
915
|
|
|
885
916
|
cowGroups[value] = {
|
|
886
917
|
id: value,
|
|
@@ -1031,7 +1062,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1031
1062
|
} else {
|
|
1032
1063
|
closeTrashcan();
|
|
1033
1064
|
}
|
|
1034
|
-
|
|
1065
|
+
}
|
|
1035
1066
|
|
|
1036
1067
|
function openTrashcan() {
|
|
1037
1068
|
$('#trashcanLidOpen').css('display', 'block');
|
|
@@ -1196,8 +1227,8 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1196
1227
|
if (cows) {
|
|
1197
1228
|
for (var i = 0; i < cows.length; i++) {
|
|
1198
1229
|
var internalCow = cows[i];
|
|
1199
|
-
if (internalCow.
|
|
1200
|
-
mark(internalCow.
|
|
1230
|
+
if (internalCow.coordinate) {
|
|
1231
|
+
mark(internalCow.coordinate, internalCow.data.group.color, 0.3, true);
|
|
1201
1232
|
}
|
|
1202
1233
|
}
|
|
1203
1234
|
}
|
|
@@ -1312,7 +1343,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1312
1343
|
nodes[0] = temp;
|
|
1313
1344
|
originNode = nodes[0];
|
|
1314
1345
|
} else if (mode === modes.ADD_HOUSE_MODE && existingNode) {
|
|
1315
|
-
// Check if same as starting node
|
|
1346
|
+
// Check if same as starting node
|
|
1316
1347
|
if (isOriginCoordinate(coordMap)) {
|
|
1317
1348
|
originNode = null;
|
|
1318
1349
|
}
|
|
@@ -1358,11 +1389,11 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1358
1389
|
mark(coordMap, 'blue', 0.3, true);
|
|
1359
1390
|
} else if (mode === modes.MARK_ORIGIN_MODE && canPlaceCFC(node)) {
|
|
1360
1391
|
mark(coordMap, 'red', 0.5, true);
|
|
1361
|
-
}
|
|
1392
|
+
}
|
|
1362
1393
|
} else if (node && houseNodes.includes(node) && mode === modes.DELETE_HOUSE_MODE) {
|
|
1363
1394
|
mark(coordMap, 'blue', 0.3, true);
|
|
1364
1395
|
}
|
|
1365
|
-
}
|
|
1396
|
+
}
|
|
1366
1397
|
};
|
|
1367
1398
|
}
|
|
1368
1399
|
|
|
@@ -1440,6 +1471,23 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1440
1471
|
};
|
|
1441
1472
|
}
|
|
1442
1473
|
|
|
1474
|
+
function draggedObjectOnGrid(e, dragged_object) {
|
|
1475
|
+
// object location is relative to the whole page, so need to factor in paper and padding size, grid canvas scroll amount, width of toolbar, etc.
|
|
1476
|
+
return e.pageX >= (TAB_PANE_WIDTH + PAPER_PADDING)
|
|
1477
|
+
&& (e.pageY + paper.scrollTop() + dragged_object.height / 2) <= (PAPER_HEIGHT + PAPER_PADDING)
|
|
1478
|
+
&& (e.pageX + paper.scrollLeft() + dragged_object.width / 2) <= (TAB_PANE_WIDTH + PAPER_WIDTH + PAPER_PADDING)
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
function getAbsCoordinates(e) {
|
|
1482
|
+
const absX = (e.pageX + paper.scrollLeft() - TAB_PANE_WIDTH) / GRID_SPACE_SIZE;
|
|
1483
|
+
const absY = (e.pageY + paper.scrollTop()) / GRID_SPACE_SIZE;
|
|
1484
|
+
return [absX, absY];
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
function draggedCursorOverGrid(absX, absY) {
|
|
1488
|
+
return absY <= SEMI_EXTENDED_PAPER_HEIGHT / 100 && absX <= EXTENDED_PAPER_WIDTH / 100 && absX >= 0
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1443
1491
|
function setupDecorListeners(decor) {
|
|
1444
1492
|
var image = decor.image;
|
|
1445
1493
|
|
|
@@ -1515,6 +1563,47 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1515
1563
|
addReleaseListeners(image.node);
|
|
1516
1564
|
}
|
|
1517
1565
|
|
|
1566
|
+
function handleDraggableDecorMouseDown(e){
|
|
1567
|
+
e.preventDefault();
|
|
1568
|
+
|
|
1569
|
+
window.dragged_decor = {};
|
|
1570
|
+
dragged_decor.pageX0 = e.pageX;
|
|
1571
|
+
dragged_decor.pageY0 = e.pageY;
|
|
1572
|
+
dragged_decor.elem = this;
|
|
1573
|
+
dragged_decor.offset0 = $(this).offset();
|
|
1574
|
+
dragged_decor.width = parseInt(currentTheme.decor[this.id].width);
|
|
1575
|
+
dragged_decor.height = parseInt(currentTheme.decor[this.id].height);
|
|
1576
|
+
dragged_decor.parent = this.parentElement;
|
|
1577
|
+
|
|
1578
|
+
const clone = $(this).clone(true);
|
|
1579
|
+
|
|
1580
|
+
function handleDraggableDecorDragging(e){
|
|
1581
|
+
const left = dragged_decor.offset0.left + (e.pageX - dragged_decor.pageX0);
|
|
1582
|
+
const top = dragged_decor.offset0.top + (e.pageY - dragged_decor.pageY0);
|
|
1583
|
+
$(dragged_decor.elem).offset({top: top, left: left});
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
function handleDraggableDecorMouseUp(e){
|
|
1587
|
+
if (dragged_decor.elem.id !== null) {
|
|
1588
|
+
if (draggedObjectOnGrid(e, dragged_decor)) {
|
|
1589
|
+
let decorObject = new InternalDecor(dragged_decor.elem.id);
|
|
1590
|
+
decorObject.setPosition(e.pageX + paper.scrollLeft() - TAB_PANE_WIDTH - dragged_decor.width / 2, e.pageY + paper.scrollTop() - dragged_decor.height / 2);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
$(document)
|
|
1595
|
+
.off('mousemove', handleDraggableDecorDragging)
|
|
1596
|
+
.off('mouseup mouseleave', handleDraggableDecorMouseUp);
|
|
1597
|
+
|
|
1598
|
+
$(dragged_decor.elem).remove();
|
|
1599
|
+
$(clone).appendTo(dragged_decor.parent);
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
$(document)
|
|
1603
|
+
.on('mouseup mouseleave', handleDraggableDecorMouseUp)
|
|
1604
|
+
.on('mousemove', handleDraggableDecorDragging);
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1518
1607
|
function setupCowListeners(cow) {
|
|
1519
1608
|
var image = cow.image;
|
|
1520
1609
|
|
|
@@ -1568,50 +1657,14 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1568
1657
|
image.transform('t' + paperX + ',' + paperY );
|
|
1569
1658
|
|
|
1570
1659
|
//Unmark the squares the cow previously occupied
|
|
1571
|
-
|
|
1572
|
-
markAsBackground(controlledCoord);
|
|
1573
|
-
}
|
|
1574
|
-
if(cows) {
|
|
1575
|
-
for( var i = 0; i < cows.length; i++){
|
|
1576
|
-
var internalCow = cows[i];
|
|
1577
|
-
if(internalCow !== cow && internalCow.controlledNode) {
|
|
1578
|
-
mark(internalCow.controlledNode.coordinate, internalCow.data.group.color, 0.3, true);
|
|
1579
|
-
}
|
|
1580
|
-
}
|
|
1581
|
-
}
|
|
1582
|
-
if (originNode) {
|
|
1583
|
-
markAsOrigin(originNode.coordinate);
|
|
1584
|
-
}
|
|
1585
|
-
if (houseNodes.length > 0) {
|
|
1586
|
-
for (let i = 0; i < houseNodes.length; i++){
|
|
1587
|
-
markAsHouse(houseNodes[i].coordinate);
|
|
1588
|
-
}
|
|
1589
|
-
}
|
|
1660
|
+
unmarkOldCowSquare(controlledCoord, cow);
|
|
1590
1661
|
|
|
1591
1662
|
// Now calculate the source coordinate
|
|
1592
1663
|
var box = image.getBBox();
|
|
1593
1664
|
var absX = (box.x + box.width/2) / GRID_SPACE_SIZE;
|
|
1594
1665
|
var absY = (box.y + box.height/2) / GRID_SPACE_SIZE;
|
|
1595
1666
|
|
|
1596
|
-
|
|
1597
|
-
var y = GRID_HEIGHT - Math.min(Math.max(0, Math.floor(absY)), GRID_HEIGHT - 1) - 1;
|
|
1598
|
-
controlledCoord = new ocargo.Coordinate(x,y);
|
|
1599
|
-
|
|
1600
|
-
// If source node is not on grid remove it
|
|
1601
|
-
if (!isCoordinateOnGrid(controlledCoord)) {
|
|
1602
|
-
controlledCoord = null;
|
|
1603
|
-
}
|
|
1604
|
-
|
|
1605
|
-
if (controlledCoord) {
|
|
1606
|
-
var colour;
|
|
1607
|
-
if(isValidPlacement(controlledCoord)) {
|
|
1608
|
-
colour = VALID_LIGHT_COLOUR;
|
|
1609
|
-
} else {
|
|
1610
|
-
colour = INVALID_LIGHT_COLOUR;
|
|
1611
|
-
}
|
|
1612
|
-
|
|
1613
|
-
mark(controlledCoord, colour, 0.7, false);
|
|
1614
|
-
}
|
|
1667
|
+
controlledCoord = markNewCowSquare(absX, absY, controlledCoord, cow);
|
|
1615
1668
|
|
|
1616
1669
|
// Deal with trashcan
|
|
1617
1670
|
var paperAbsX = paperX - paper.scrollLeft() + imageWidth/2;
|
|
@@ -1628,6 +1681,8 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1628
1681
|
}
|
|
1629
1682
|
|
|
1630
1683
|
function onDragStart(x, y) {
|
|
1684
|
+
// cow shouldn't be in the cow group during dragging
|
|
1685
|
+
removeCowFromCowList(cow);
|
|
1631
1686
|
var bBox = image.getBBox();
|
|
1632
1687
|
imageWidth = bBox.width;
|
|
1633
1688
|
imageHeight = bBox.height;
|
|
@@ -1643,71 +1698,62 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1643
1698
|
}
|
|
1644
1699
|
|
|
1645
1700
|
function onDragEnd() {
|
|
1646
|
-
//Unmark previously occupied square
|
|
1647
|
-
if(cow.controlledNode) {
|
|
1648
|
-
markAsBackground(cow.controlledNode.coordinate);
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
// Mark squares currently occupied
|
|
1652
|
-
if (controlledCoord) {
|
|
1653
|
-
mark(controlledCoord, cow.data.group.color, 0.3, true);
|
|
1654
|
-
}
|
|
1655
|
-
if (originNode) {
|
|
1656
|
-
markAsOrigin(originNode.coordinate);
|
|
1657
|
-
}
|
|
1658
|
-
if (houseNodes.length > 0) {
|
|
1659
|
-
for (let i = 0; i < houseNodes.length; i++) {
|
|
1660
|
-
markAsHouse(houseNodes[i].coordinate);
|
|
1661
|
-
}
|
|
1662
|
-
}
|
|
1663
1701
|
|
|
1664
1702
|
if (trashcanOpen) {
|
|
1665
1703
|
cow.destroy();
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
var controlledNode = ocargo.Node.findNodeByCoordinate(controlledCoord, nodes);
|
|
1669
|
-
cow.controlledNode = controlledNode;
|
|
1670
|
-
cow.valid = true;
|
|
1671
|
-
drawing.setCowImagePosition(controlledCoord, image, controlledNode);
|
|
1704
|
+
unmarkOldCowSquare(controlledCoord, cow);
|
|
1705
|
+
closeTrashcan();
|
|
1672
1706
|
} else {
|
|
1673
|
-
cow
|
|
1674
|
-
cow
|
|
1707
|
+
setCowMarkingsOnMouseUp(controlledCoord, cow);
|
|
1708
|
+
cows.push(cow);
|
|
1709
|
+
cow.coordinate = controlledCoord;
|
|
1710
|
+
cow.valid = isValidDraggedCowPlacement(controlledCoord, cow);
|
|
1711
|
+
if (cow.isOnRoad()) {
|
|
1712
|
+
const controlledNode = ocargo.Node.findNodeByCoordinate(controlledCoord, nodes);
|
|
1713
|
+
drawing.setCowImagePosition(controlledCoord, image, controlledNode);
|
|
1714
|
+
}
|
|
1715
|
+
else {
|
|
1716
|
+
var cowX = paperX;
|
|
1717
|
+
var cowY = paperY;
|
|
1675
1718
|
|
|
1676
|
-
|
|
1677
|
-
|
|
1719
|
+
if (paperWidth < paperX + imageWidth) {
|
|
1720
|
+
cowX = paperWidth - imageWidth
|
|
1721
|
+
}
|
|
1678
1722
|
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1723
|
+
if (paperHeight < paperY + imageHeight) {
|
|
1724
|
+
cowY = paperHeight - imageHeight
|
|
1725
|
+
}
|
|
1682
1726
|
|
|
1683
|
-
|
|
1684
|
-
cowY = paperHeight - imageHeight
|
|
1727
|
+
image.transform('t' + cowX + ',' + cowY);
|
|
1685
1728
|
}
|
|
1729
|
+
}
|
|
1686
1730
|
|
|
1687
|
-
image.transform('t' + cowX + ',' + cowY);
|
|
1688
|
-
}
|
|
1689
1731
|
adjustCowGroupMinMaxFields(cow);
|
|
1690
|
-
|
|
1691
1732
|
image.attr({'cursor':'pointer'});
|
|
1692
|
-
closeTrashcan();
|
|
1693
|
-
}
|
|
1694
|
-
|
|
1695
|
-
function isValidPlacement(controlledCoord){
|
|
1696
|
-
var controlledNode = ocargo.Node.findNodeByCoordinate(controlledCoord, nodes);
|
|
1697
|
-
if (!controlledNode)
|
|
1698
|
-
return false;
|
|
1699
|
-
for (var i=0; i < cows.length; i++) {
|
|
1700
|
-
var otherCow = cows[i];
|
|
1701
|
-
if (otherCow.controlledNode == controlledNode && cow != otherCow)
|
|
1702
|
-
return false;
|
|
1703
|
-
}
|
|
1704
|
-
return true;
|
|
1705
1733
|
}
|
|
1706
1734
|
|
|
1707
1735
|
image.drag(onDragMove, onDragStart, onDragEnd);
|
|
1708
1736
|
addReleaseListeners(image.node);
|
|
1709
1737
|
}
|
|
1710
1738
|
|
|
1739
|
+
function removeCowFromCowList(cow) {
|
|
1740
|
+
var index = cows.indexOf(cow);
|
|
1741
|
+
if (index > -1) {
|
|
1742
|
+
cows.splice(index, 1);
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
function isValidDraggedCowPlacement(controlledCoord, cow){
|
|
1747
|
+
if (isOriginCoordinate(controlledCoord) || isHouseCoordinate(controlledCoord))
|
|
1748
|
+
return false;
|
|
1749
|
+
for (var i=0; i < cows.length; i++) {
|
|
1750
|
+
var otherCow = cows[i];
|
|
1751
|
+
if (cow != otherCow && otherCow.coordinate && otherCow.coordinate.equals(controlledCoord))
|
|
1752
|
+
return false;
|
|
1753
|
+
}
|
|
1754
|
+
return true;
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1711
1757
|
function adjustCowGroupMinMaxFields(draggedCow) {
|
|
1712
1758
|
var draggedCowGroupId = draggedCow.data.group.id;
|
|
1713
1759
|
|
|
@@ -1724,6 +1770,131 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1724
1770
|
$('#cow_group_select').val(draggedCowGroupId).change();
|
|
1725
1771
|
}
|
|
1726
1772
|
|
|
1773
|
+
function unmarkOldCowSquare(controlledCoord, cow = "undefined") {
|
|
1774
|
+
if (controlledCoord) {
|
|
1775
|
+
markAsBackground(controlledCoord);
|
|
1776
|
+
}
|
|
1777
|
+
if (originNode) {
|
|
1778
|
+
markAsOrigin(originNode.coordinate);
|
|
1779
|
+
}
|
|
1780
|
+
if (houseNodes.length > 0) {
|
|
1781
|
+
for (let i = 0; i < houseNodes.length; i++){
|
|
1782
|
+
markAsHouse(houseNodes[i].coordinate);
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
function setCowMarkingsOnMouseUp(controlledCoord, cow) {
|
|
1788
|
+
if (cow.isOnRoad()) {
|
|
1789
|
+
markAsBackground(cow.coordinate);
|
|
1790
|
+
}
|
|
1791
|
+
if (controlledCoord) {
|
|
1792
|
+
mark(controlledCoord, cow.data.group.color, 0.3, true);
|
|
1793
|
+
}
|
|
1794
|
+
if (originNode) {
|
|
1795
|
+
markAsOrigin(originNode.coordinate);
|
|
1796
|
+
}
|
|
1797
|
+
if (houseNodes.length > 0) {
|
|
1798
|
+
for (let i = 0; i < houseNodes.length; i++) {
|
|
1799
|
+
markAsHouse(houseNodes[i].coordinate);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
function markNewCowSquare(absX, absY, controlledCoord, cow = "undefined") {
|
|
1805
|
+
const x = Math.min(Math.max(0, Math.floor(absX)), GRID_WIDTH - 1);
|
|
1806
|
+
const y = GRID_HEIGHT - Math.min(Math.max(0, Math.floor(absY)), GRID_HEIGHT - 1) - 1;
|
|
1807
|
+
controlledCoord = new ocargo.Coordinate(x,y);
|
|
1808
|
+
|
|
1809
|
+
// If source node is not on grid remove it
|
|
1810
|
+
if (!isCoordinateOnGrid(controlledCoord)) {
|
|
1811
|
+
controlledCoord = null;
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
// mark square valid or invalid
|
|
1815
|
+
if (controlledCoord) {
|
|
1816
|
+
let colour;
|
|
1817
|
+
if(isValidDraggedCowPlacement(controlledCoord, cow)) {
|
|
1818
|
+
colour = VALID_LIGHT_COLOUR;
|
|
1819
|
+
} else {
|
|
1820
|
+
colour = INVALID_LIGHT_COLOUR;
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
mark(controlledCoord, colour, 0.7, false);
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
return controlledCoord;
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
function handleDraggableCowMouseDown(e, cowGroup){
|
|
1830
|
+
e.preventDefault();
|
|
1831
|
+
|
|
1832
|
+
window.dragged_cow = {};
|
|
1833
|
+
dragged_cow.pageX0 = e.pageX;
|
|
1834
|
+
dragged_cow.pageY0 = e.pageY;
|
|
1835
|
+
dragged_cow.elem = e.target;
|
|
1836
|
+
dragged_cow.offset0 = $(e.target).offset();
|
|
1837
|
+
dragged_cow.parent = e.target.parentElement;
|
|
1838
|
+
dragged_cow.group = cowGroups[cowGroup];
|
|
1839
|
+
dragged_cow.width = COW_WIDTH;
|
|
1840
|
+
dragged_cow.height = COW_HEIGHT;
|
|
1841
|
+
|
|
1842
|
+
const clone = $(e.target).clone(true);
|
|
1843
|
+
let controlledCoord;
|
|
1844
|
+
|
|
1845
|
+
function handleDraggableCowDragging(e){
|
|
1846
|
+
e.target.style.cursor = "pointer";
|
|
1847
|
+
|
|
1848
|
+
const left = dragged_cow.offset0.left + (e.pageX - dragged_cow.pageX0);
|
|
1849
|
+
const top = dragged_cow.offset0.top + (e.pageY - dragged_cow.pageY0);
|
|
1850
|
+
$(dragged_cow.elem).offset({top: top, left: left});
|
|
1851
|
+
|
|
1852
|
+
unmarkOldCowSquare(controlledCoord);
|
|
1853
|
+
|
|
1854
|
+
const [absX, absY] = getAbsCoordinates(e);
|
|
1855
|
+
if (draggedCursorOverGrid(absX, absY)) {
|
|
1856
|
+
controlledCoord = markNewCowSquare(absX, absY, controlledCoord);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
function handleDraggableCowMouseUp(e){
|
|
1861
|
+
let internalCow = new InternalCow({group: cowGroups["group1"]});
|
|
1862
|
+
let image = internalCow.image;
|
|
1863
|
+
internalCow.coordinate = controlledCoord;
|
|
1864
|
+
internalCow.valid = isValidDraggedCowPlacement(controlledCoord, internalCow);
|
|
1865
|
+
|
|
1866
|
+
if (internalCow.isOnRoad()) {
|
|
1867
|
+
const controlledNode = ocargo.Node.findNodeByCoordinate(controlledCoord, nodes);
|
|
1868
|
+
drawing.setCowImagePosition(controlledCoord, image, controlledNode);
|
|
1869
|
+
} else {
|
|
1870
|
+
const cowX = e.pageX + paper.scrollLeft() - TAB_PANE_WIDTH - dragged_cow.width / 2;
|
|
1871
|
+
const cowY = e.pageY + paper.scrollTop() - dragged_cow.height / 2;
|
|
1872
|
+
|
|
1873
|
+
if (draggedObjectOnGrid(e, dragged_cow)) {
|
|
1874
|
+
image.transform('t' + cowX + ',' + cowY);
|
|
1875
|
+
} else {
|
|
1876
|
+
internalCow.destroy();
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
if (!trashcanOpen) {
|
|
1881
|
+
setCowMarkingsOnMouseUp(controlledCoord, internalCow);
|
|
1882
|
+
adjustCowGroupMinMaxFields(internalCow);
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
$(document)
|
|
1886
|
+
.off('mousemove', handleDraggableCowDragging)
|
|
1887
|
+
.off('mouseup mouseleave', handleDraggableCowMouseUp);
|
|
1888
|
+
|
|
1889
|
+
$(dragged_cow.elem).remove();
|
|
1890
|
+
$(clone).appendTo(dragged_cow.parent);
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
$(document)
|
|
1894
|
+
.on('mouseup mouseleave', handleDraggableCowMouseUp)
|
|
1895
|
+
.on('mousemove', handleDraggableCowDragging);
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1727
1898
|
|
|
1728
1899
|
function setupTrafficLightListeners(trafficLight) {
|
|
1729
1900
|
var image = trafficLight.image;
|
|
@@ -1788,23 +1959,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1788
1959
|
image.transform('t' + paperX + ',' + paperY + 'r' + rotation + 's' + scaling);
|
|
1789
1960
|
|
|
1790
1961
|
// Unmark the squares the light previously occupied
|
|
1791
|
-
|
|
1792
|
-
markAsBackground(sourceCoord);
|
|
1793
|
-
}
|
|
1794
|
-
if (controlledCoord) {
|
|
1795
|
-
markAsBackground(controlledCoord);
|
|
1796
|
-
}
|
|
1797
|
-
|
|
1798
|
-
markCowNodes();
|
|
1799
|
-
|
|
1800
|
-
if (originNode) {
|
|
1801
|
-
markAsOrigin(originNode.coordinate);
|
|
1802
|
-
}
|
|
1803
|
-
if (houseNodes.length > 0) {
|
|
1804
|
-
for (let i = 0; i < houseNodes.length; i++) {
|
|
1805
|
-
markAsHouse(houseNodes[i].coordinate);
|
|
1806
|
-
}
|
|
1807
|
-
}
|
|
1962
|
+
unmarkOldTrafficLightSquare(sourceCoord, controlledCoord);
|
|
1808
1963
|
|
|
1809
1964
|
// Now calculate the source coordinate
|
|
1810
1965
|
var box = image.getBBox();
|
|
@@ -1826,48 +1981,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1826
1981
|
break;
|
|
1827
1982
|
}
|
|
1828
1983
|
|
|
1829
|
-
|
|
1830
|
-
var y = GRID_HEIGHT - Math.min(Math.max(0, Math.floor(absY)), GRID_HEIGHT - 1) - 1;
|
|
1831
|
-
sourceCoord = new ocargo.Coordinate(x,y);
|
|
1832
|
-
|
|
1833
|
-
// Find controlled position in map coordinates
|
|
1834
|
-
switch(rotation) {
|
|
1835
|
-
case 0:
|
|
1836
|
-
controlledCoord = new ocargo.Coordinate(sourceCoord.x, sourceCoord.y + 1);
|
|
1837
|
-
break;
|
|
1838
|
-
case 90:
|
|
1839
|
-
controlledCoord = new ocargo.Coordinate(sourceCoord.x + 1, sourceCoord.y);
|
|
1840
|
-
break;
|
|
1841
|
-
case 180:
|
|
1842
|
-
controlledCoord = new ocargo.Coordinate(sourceCoord.x, sourceCoord.y - 1);
|
|
1843
|
-
break;
|
|
1844
|
-
case 270:
|
|
1845
|
-
controlledCoord = new ocargo.Coordinate(sourceCoord.x - 1, sourceCoord.y);
|
|
1846
|
-
break;
|
|
1847
|
-
}
|
|
1848
|
-
|
|
1849
|
-
// If controlled node is not on grid, remove it
|
|
1850
|
-
if (!isCoordinateOnGrid(controlledCoord)) {
|
|
1851
|
-
controlledCoord = null;
|
|
1852
|
-
}
|
|
1853
|
-
|
|
1854
|
-
// If source node is not on grid remove it
|
|
1855
|
-
if (!isCoordinateOnGrid(sourceCoord)) {
|
|
1856
|
-
sourceCoord = null;
|
|
1857
|
-
}
|
|
1858
|
-
|
|
1859
|
-
if (sourceCoord && controlledCoord) {
|
|
1860
|
-
var colour;
|
|
1861
|
-
if(isValidPlacement(sourceCoord, controlledCoord)) {
|
|
1862
|
-
colour = VALID_LIGHT_COLOUR;
|
|
1863
|
-
drawing.setTrafficLightImagePosition(sourceCoord, controlledCoord, image);
|
|
1864
|
-
} else {
|
|
1865
|
-
colour = INVALID_LIGHT_COLOUR;
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1868
|
-
mark(controlledCoord, colour, 0.7, false);
|
|
1869
|
-
mark(sourceCoord, colour, 0.7, false);
|
|
1870
|
-
}
|
|
1984
|
+
[sourceCoord, controlledCoord] = markNewTrafficLightSquare(absX, absY, isValidTrafficLightPlacement, sourceCoord, controlledCoord, rotation, image);
|
|
1871
1985
|
|
|
1872
1986
|
// Deal with trashcan
|
|
1873
1987
|
var paperAbsX = paperX - paper.scrollLeft() + imageWidth/2;
|
|
@@ -1907,27 +2021,11 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1907
2021
|
|
|
1908
2022
|
function onDragEnd() {
|
|
1909
2023
|
// Unmark squares currently occupied
|
|
1910
|
-
|
|
1911
|
-
markAsBackground(sourceCoord);
|
|
1912
|
-
}
|
|
1913
|
-
if (controlledCoord) {
|
|
1914
|
-
markAsBackground(controlledCoord);
|
|
1915
|
-
}
|
|
1916
|
-
|
|
1917
|
-
markCowNodes();
|
|
1918
|
-
|
|
1919
|
-
if (originNode) {
|
|
1920
|
-
markAsOrigin(originNode.coordinate);
|
|
1921
|
-
}
|
|
1922
|
-
if (houseNodes.length > 0) {
|
|
1923
|
-
for (let i = 0; i < houseNodes.length; i++) {
|
|
1924
|
-
markAsHouse(houseNodes[i].coordinate);
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
2024
|
+
unmarkOldTrafficLightSquare(sourceCoord, controlledCoord);
|
|
1927
2025
|
|
|
1928
2026
|
if(trashcanOpen) {
|
|
1929
2027
|
trafficLight.destroy();
|
|
1930
|
-
} else if(
|
|
2028
|
+
} else if(isValidTrafficLightPlacement(sourceCoord, controlledCoord)) {
|
|
1931
2029
|
// Add back to the list of traffic lights if on valid nodes
|
|
1932
2030
|
trafficLight.sourceNode = ocargo.Node.findNodeByCoordinate(sourceCoord, nodes);
|
|
1933
2031
|
trafficLight.controlledNode = ocargo.Node.findNodeByCoordinate(controlledCoord, nodes);
|
|
@@ -1976,41 +2074,177 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
1976
2074
|
}
|
|
1977
2075
|
return "0,0";
|
|
1978
2076
|
}
|
|
2077
|
+
}
|
|
1979
2078
|
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
2079
|
+
function isValidTrafficLightPlacement(sourceCoord, controlledCoord) {
|
|
2080
|
+
var sourceNode = ocargo.Node.findNodeByCoordinate(sourceCoord, nodes);
|
|
2081
|
+
var controlledNode = ocargo.Node.findNodeByCoordinate(controlledCoord, nodes);
|
|
1983
2082
|
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
}
|
|
2083
|
+
// Test if two connected nodes exist
|
|
2084
|
+
var connected = false;
|
|
2085
|
+
if (sourceNode && controlledNode) {
|
|
2086
|
+
for (var i = 0; i < sourceNode.connectedNodes.length; i++) {
|
|
2087
|
+
if (sourceNode.connectedNodes[i] === controlledNode) {
|
|
2088
|
+
connected = true;
|
|
2089
|
+
break;
|
|
1992
2090
|
}
|
|
1993
2091
|
}
|
|
2092
|
+
}
|
|
1994
2093
|
|
|
1995
|
-
|
|
2094
|
+
if(!connected) {
|
|
2095
|
+
return false;
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
// Test it's not already occupied
|
|
2099
|
+
for(var i = 0; i < trafficLights.length; i++) {
|
|
2100
|
+
var tl = trafficLights[i];
|
|
2101
|
+
if(tl.valid &&
|
|
2102
|
+
((tl.sourceNode === sourceNode && tl.controlledNode === controlledNode) ||
|
|
2103
|
+
(tl.sourceNode === controlledNode && tl.controlledNode === sourceNode))) {
|
|
1996
2104
|
return false;
|
|
1997
2105
|
}
|
|
2106
|
+
}
|
|
2107
|
+
return true;
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
function unmarkOldTrafficLightSquare(sourceCoord, controlledCoord) {
|
|
2111
|
+
// Unmark the squares the light previously occupied
|
|
2112
|
+
if (sourceCoord) {
|
|
2113
|
+
markAsBackground(sourceCoord);
|
|
2114
|
+
}
|
|
2115
|
+
if (controlledCoord) {
|
|
2116
|
+
markAsBackground(controlledCoord);
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
markCowNodes();
|
|
2120
|
+
|
|
2121
|
+
if (originNode) {
|
|
2122
|
+
markAsOrigin(originNode.coordinate);
|
|
2123
|
+
}
|
|
2124
|
+
if (houseNodes.length > 0) {
|
|
2125
|
+
for (let i = 0; i < houseNodes.length; i++) {
|
|
2126
|
+
markAsHouse(houseNodes[i].coordinate);
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
function markNewTrafficLightSquare(absX, absY, validityCheckFunction, sourceCoord, controlledCoord, rotation, image = "undefined") {
|
|
2132
|
+
var x = Math.min(Math.max(0, Math.floor(absX)), GRID_WIDTH - 1);
|
|
2133
|
+
var y = GRID_HEIGHT - Math.min(Math.max(0, Math.floor(absY)), GRID_HEIGHT - 1) - 1;
|
|
2134
|
+
sourceCoord = new ocargo.Coordinate(x,y);
|
|
1998
2135
|
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2136
|
+
// Find controlled position in map coordinates
|
|
2137
|
+
switch(rotation) {
|
|
2138
|
+
case 0:
|
|
2139
|
+
controlledCoord = new ocargo.Coordinate(sourceCoord.x, sourceCoord.y + 1);
|
|
2140
|
+
break;
|
|
2141
|
+
case 90:
|
|
2142
|
+
controlledCoord = new ocargo.Coordinate(sourceCoord.x + 1, sourceCoord.y);
|
|
2143
|
+
break;
|
|
2144
|
+
case 180:
|
|
2145
|
+
controlledCoord = new ocargo.Coordinate(sourceCoord.x, sourceCoord.y - 1);
|
|
2146
|
+
break;
|
|
2147
|
+
case 270:
|
|
2148
|
+
controlledCoord = new ocargo.Coordinate(sourceCoord.x - 1, sourceCoord.y);
|
|
2149
|
+
break;
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
// If controlled node is not on grid, remove it
|
|
2153
|
+
if (!isCoordinateOnGrid(controlledCoord)) {
|
|
2154
|
+
controlledCoord = null;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
// If source node is not on grid remove it
|
|
2158
|
+
if (!isCoordinateOnGrid(sourceCoord)) {
|
|
2159
|
+
sourceCoord = null;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
if (sourceCoord && controlledCoord) {
|
|
2163
|
+
var colour;
|
|
2164
|
+
if(validityCheckFunction(sourceCoord, controlledCoord)) {
|
|
2165
|
+
colour = VALID_LIGHT_COLOUR;
|
|
2166
|
+
if (image !== "undefined") {
|
|
2167
|
+
drawing.setTrafficLightImagePosition(sourceCoord, controlledCoord, image);
|
|
2006
2168
|
}
|
|
2169
|
+
} else {
|
|
2170
|
+
colour = INVALID_LIGHT_COLOUR;
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
mark(controlledCoord, colour, 0.7, false);
|
|
2174
|
+
mark(sourceCoord, colour, 0.7, false);
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
return [sourceCoord, controlledCoord];
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
function handleDraggableTrafficLightsMouseDown(e, startingState){
|
|
2181
|
+
e.preventDefault();
|
|
2182
|
+
|
|
2183
|
+
window.dragged_light = {};
|
|
2184
|
+
dragged_light.pageX0 = e.pageX;
|
|
2185
|
+
dragged_light.pageY0 = e.pageY;
|
|
2186
|
+
dragged_light.elem = e.target;
|
|
2187
|
+
dragged_light.offset0 = $(e.target).offset();
|
|
2188
|
+
dragged_light.width = TRAFFIC_LIGHT_WIDTH;
|
|
2189
|
+
dragged_light.height = TRAFFIC_LIGHT_HEIGHT;
|
|
2190
|
+
dragged_light.parent = e.target.parentElement;
|
|
2191
|
+
|
|
2192
|
+
const clone = $(e.target).clone(true);
|
|
2193
|
+
|
|
2194
|
+
let sourceCoord;
|
|
2195
|
+
let controlledCoord;
|
|
2196
|
+
|
|
2197
|
+
function handleDraggableTrafficLightsDragging(e){
|
|
2198
|
+
const left = dragged_light.offset0.left + (e.pageX - dragged_light.pageX0);
|
|
2199
|
+
const top = dragged_light.offset0.top + (e.pageY - dragged_light.pageY0);
|
|
2200
|
+
$(dragged_light.elem).offset({top: top, left: left});
|
|
2201
|
+
|
|
2202
|
+
unmarkOldTrafficLightSquare(sourceCoord, controlledCoord);
|
|
2203
|
+
|
|
2204
|
+
const [absX, absY] = getAbsCoordinates(e);
|
|
2205
|
+
if (draggedCursorOverGrid(absX, absY)) {
|
|
2206
|
+
[sourceCoord, controlledCoord] = markNewTrafficLightSquare(absX, absY, isValidTrafficLightPlacement, sourceCoord, controlledCoord, 0);
|
|
2007
2207
|
}
|
|
2008
|
-
return true;
|
|
2009
2208
|
}
|
|
2010
2209
|
|
|
2011
|
-
function
|
|
2210
|
+
function handleDraggableTrafficLightsMouseUp(e){
|
|
2211
|
+
let internalTrafficLight = new InternalTrafficLight({"redDuration": 3, "greenDuration": 3, "startTime": 0, "startingState": startingState, "sourceCoordinate": null, "direction": null});
|
|
2212
|
+
let image = internalTrafficLight.image;
|
|
2213
|
+
|
|
2214
|
+
const lightX = e.pageX + paper.scrollLeft() - TAB_PANE_WIDTH - dragged_light.width;
|
|
2215
|
+
const lightY = e.pageY + paper.scrollTop() - dragged_light.width / 2;
|
|
2216
|
+
|
|
2217
|
+
unmarkOldTrafficLightSquare(sourceCoord, controlledCoord);
|
|
2012
2218
|
|
|
2219
|
+
if (isValidTrafficLightPlacement(sourceCoord, controlledCoord)) {
|
|
2220
|
+
internalTrafficLight.sourceNode = ocargo.Node.findNodeByCoordinate(sourceCoord, nodes);
|
|
2221
|
+
internalTrafficLight.controlledNode = ocargo.Node.findNodeByCoordinate(controlledCoord, nodes);
|
|
2222
|
+
internalTrafficLight.valid = true;
|
|
2223
|
+
|
|
2224
|
+
drawing.setTrafficLightImagePosition(sourceCoord, controlledCoord, image);
|
|
2225
|
+
} else {
|
|
2226
|
+
internalTrafficLight.sourceCoord = null;
|
|
2227
|
+
internalTrafficLight.controlledCoord = null;
|
|
2228
|
+
internalTrafficLight.valid = false;
|
|
2229
|
+
|
|
2230
|
+
if (draggedObjectOnGrid(e, dragged_light)) {
|
|
2231
|
+
image.transform('t' + lightX + ',' + lightY + ' s-1,1');
|
|
2232
|
+
} else {
|
|
2233
|
+
internalTrafficLight.destroy();
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
$(document)
|
|
2238
|
+
.off('mousemove', handleDraggableTrafficLightsDragging)
|
|
2239
|
+
.off('mouseup mouseleave', handleDraggableTrafficLightsMouseUp);
|
|
2240
|
+
|
|
2241
|
+
$(dragged_light.elem).remove();
|
|
2242
|
+
$(clone).appendTo(dragged_light.parent);
|
|
2013
2243
|
}
|
|
2244
|
+
|
|
2245
|
+
$(document)
|
|
2246
|
+
.on('mouseup mouseleave', handleDraggableTrafficLightsMouseUp)
|
|
2247
|
+
.on('mousemove', handleDraggableTrafficLightsDragging);
|
|
2014
2248
|
}
|
|
2015
2249
|
|
|
2016
2250
|
/********************************/
|
|
@@ -2143,6 +2377,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2143
2377
|
|
|
2144
2378
|
function setTheme(theme) {
|
|
2145
2379
|
currentTheme = theme;
|
|
2380
|
+
let newType = currentTheme == THEMES.city ? ocargo.Cow.PIGEON : ocargo.Cow.WHITE;
|
|
2146
2381
|
|
|
2147
2382
|
for (var x = 0; x < GRID_WIDTH; x++) {
|
|
2148
2383
|
for (var y = 0; y < GRID_HEIGHT; y++) {
|
|
@@ -2159,6 +2394,36 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2159
2394
|
});
|
|
2160
2395
|
|
|
2161
2396
|
$('#paper').css({'background-color': theme.background});
|
|
2397
|
+
|
|
2398
|
+
const animalSource = theme == THEMES.city ? "/static/game/image/pigeon.svg" : "/static/game/image/Clarice.svg";
|
|
2399
|
+
|
|
2400
|
+
$('#cow').each(function(index, element) {
|
|
2401
|
+
element.src = animalSource;
|
|
2402
|
+
})
|
|
2403
|
+
|
|
2404
|
+
$('#animals_label').each(function(index, element) {
|
|
2405
|
+
element.innerHTML = theme == THEMES.city ? "Pigeons" : "Cows";
|
|
2406
|
+
})
|
|
2407
|
+
|
|
2408
|
+
for (let [key, value] of Object.entries(cowGroups)) {
|
|
2409
|
+
value["type"] = theme == THEMES.city ? ocargo.Cow.PIGEON : ocargo.Cow.WHITE;
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
for (let i = 0; i < cows.length; i++) {
|
|
2413
|
+
cows[i].updateTheme();
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
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
|
|
2417
|
+
"><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
|
|
2418
|
+
"></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
|
|
2419
|
+
"></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>`;
|
|
2420
|
+
|
|
2421
|
+
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
|
|
2422
|
+
"><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
|
|
2423
|
+
"></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
|
|
2424
|
+
"></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>`;
|
|
2425
|
+
|
|
2426
|
+
$("#cow_crossing_image").html(newType == ocargo.Cow.PIGEON ? pigeonHTML : cowHTML);
|
|
2162
2427
|
}
|
|
2163
2428
|
|
|
2164
2429
|
function sortNodes(nodes) {
|
|
@@ -2225,7 +2490,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2225
2490
|
type: cowGroups[groupId].type}; //editor can only add white cow for now
|
|
2226
2491
|
}
|
|
2227
2492
|
|
|
2228
|
-
var coordinates = cows[i].
|
|
2493
|
+
var coordinates = cows[i].coordinate;
|
|
2229
2494
|
var strCoordinates = {'x':coordinates.x, 'y':coordinates.y};
|
|
2230
2495
|
cowGroupData[groupId].potentialCoordinates.push(strCoordinates);
|
|
2231
2496
|
}
|
|
@@ -2277,13 +2542,65 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2277
2542
|
|
|
2278
2543
|
// Language data
|
|
2279
2544
|
var language = $('#language_select').val();
|
|
2280
|
-
state.
|
|
2281
|
-
state.
|
|
2282
|
-
state.
|
|
2545
|
+
state.blockly_enabled = language === 'blockly' || language === 'both' || language === 'blocklyWithPythonView';
|
|
2546
|
+
state.python_view_enabled = language === 'blocklyWithPythonView';
|
|
2547
|
+
state.python_enabled = language === 'python' || language === 'both';
|
|
2548
|
+
|
|
2549
|
+
const regex = /^[\w.?!', ]*$/;
|
|
2550
|
+
const subtitleValue = $('#subtitle').val();
|
|
2551
|
+
const descriptionValue = $('#description').val();
|
|
2552
|
+
const hintValue = $('#hint').val();
|
|
2553
|
+
|
|
2554
|
+
// Description and hint data
|
|
2555
|
+
if (subtitleValue.length > 0) {
|
|
2556
|
+
if (regex.exec(subtitleValue)) {
|
|
2557
|
+
state.subtitle = subtitleValue;
|
|
2558
|
+
}
|
|
2559
|
+
else {
|
|
2560
|
+
ocargo.Drawing.startPopup(
|
|
2561
|
+
"Oh no!",
|
|
2562
|
+
"You used some invalid characters for your level subtitle.",
|
|
2563
|
+
"Try saving your level again using only" +
|
|
2564
|
+
" letters, numbers and standard punctuation."
|
|
2565
|
+
);
|
|
2566
|
+
return
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
if (descriptionValue.length > 0) {
|
|
2571
|
+
if (regex.exec(descriptionValue)) {
|
|
2572
|
+
state.lesson = descriptionValue;
|
|
2573
|
+
}
|
|
2574
|
+
else {
|
|
2575
|
+
ocargo.Drawing.startPopup(
|
|
2576
|
+
"Oh no!",
|
|
2577
|
+
"You used some invalid characters for your level description.",
|
|
2578
|
+
"Try saving your level again using only" +
|
|
2579
|
+
" letters and numbers and standard punctuation."
|
|
2580
|
+
);
|
|
2581
|
+
return
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
if (hintValue.length > 0) {
|
|
2586
|
+
if (regex.exec(hintValue)) {
|
|
2587
|
+
state.hint = hintValue;
|
|
2588
|
+
}
|
|
2589
|
+
else {
|
|
2590
|
+
ocargo.Drawing.startPopup(
|
|
2591
|
+
"Oh no!",
|
|
2592
|
+
"You used some invalid characters for your level hint.",
|
|
2593
|
+
"Try saving your level again using only" +
|
|
2594
|
+
" letters and numbers and standard punctuation."
|
|
2595
|
+
);
|
|
2596
|
+
return
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2283
2599
|
|
|
2284
2600
|
// Other data
|
|
2285
2601
|
state.theme = currentTheme.id;
|
|
2286
2602
|
state.character = $('#character_select').val();
|
|
2603
|
+
state.disable_algorithm_score = true;
|
|
2287
2604
|
|
|
2288
2605
|
return state;
|
|
2289
2606
|
}
|
|
@@ -2291,6 +2608,17 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2291
2608
|
function restoreState(state) {
|
|
2292
2609
|
console.log("restoring state");
|
|
2293
2610
|
|
|
2611
|
+
// Get character id from saved character name
|
|
2612
|
+
var characterName = state.character_name;
|
|
2613
|
+
if (characterName) {
|
|
2614
|
+
var characterId = null;
|
|
2615
|
+
for (var id in CHARACTERS) {
|
|
2616
|
+
if (characterName == CHARACTERS[id].name) {
|
|
2617
|
+
characterId = id;
|
|
2618
|
+
break;
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2294
2622
|
clear();
|
|
2295
2623
|
|
|
2296
2624
|
// Load node data
|
|
@@ -2302,35 +2630,6 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2302
2630
|
new InternalTrafficLight(trafficLightData[i]);
|
|
2303
2631
|
}
|
|
2304
2632
|
|
|
2305
|
-
if(COW_LEVELS_ENABLED) {
|
|
2306
|
-
var cowGroupData = JSON.parse(state.cows);
|
|
2307
|
-
for (var i = 0; i < cowGroupData.length; i++) {
|
|
2308
|
-
// Add new group to group select element
|
|
2309
|
-
if (i >= Object.keys(cowGroups).length) {
|
|
2310
|
-
addCowGroup();
|
|
2311
|
-
}
|
|
2312
|
-
var cowGroupId = Object.keys(cowGroups)[i];
|
|
2313
|
-
cowGroups[cowGroupId].minCows = cowGroupData[i].minCows;
|
|
2314
|
-
cowGroups[cowGroupId].maxCows = cowGroupData[i].maxCows;
|
|
2315
|
-
cowGroups[cowGroupId].type = cowGroupData[i].type;
|
|
2316
|
-
|
|
2317
|
-
if (cowGroupData[i].potentialCoordinates != null) {
|
|
2318
|
-
for (var j = 0; j < cowGroupData[i].potentialCoordinates.length; j++) {
|
|
2319
|
-
var cowData = {
|
|
2320
|
-
coordinates: [cowGroupData[i].potentialCoordinates[j]],
|
|
2321
|
-
group: cowGroups[cowGroupId]
|
|
2322
|
-
};
|
|
2323
|
-
new InternalCow(cowData);
|
|
2324
|
-
}
|
|
2325
|
-
}
|
|
2326
|
-
}
|
|
2327
|
-
|
|
2328
|
-
// Trigger change listener on cow group select box to set initial min/max values
|
|
2329
|
-
$('#cow_group_select').change();
|
|
2330
|
-
|
|
2331
|
-
markCowNodes();
|
|
2332
|
-
}
|
|
2333
|
-
|
|
2334
2633
|
// Load in destination and origin nodes
|
|
2335
2634
|
if (state.destinations) {
|
|
2336
2635
|
var houses = JSON.parse(state.destinations);
|
|
@@ -2349,7 +2648,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2349
2648
|
}
|
|
2350
2649
|
|
|
2351
2650
|
// Load in character
|
|
2352
|
-
$('#character_select').val(
|
|
2651
|
+
$('#character_select').val(characterId);
|
|
2353
2652
|
$('#character_select').change();
|
|
2354
2653
|
|
|
2355
2654
|
drawAll();
|
|
@@ -2378,6 +2677,36 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2378
2677
|
PAPER_HEIGHT - currentTheme.decor[decor[i].decorName].height - decor[i].y + PAPER_PADDING);
|
|
2379
2678
|
}
|
|
2380
2679
|
|
|
2680
|
+
//Load in cow data
|
|
2681
|
+
if(COW_LEVELS_ENABLED) {
|
|
2682
|
+
var cowGroupData = JSON.parse(state.cows);
|
|
2683
|
+
for (var i = 0; i < cowGroupData.length; i++) {
|
|
2684
|
+
// Add new group to group select element
|
|
2685
|
+
if (i >= Object.keys(cowGroups).length) {
|
|
2686
|
+
addCowGroup();
|
|
2687
|
+
}
|
|
2688
|
+
var cowGroupId = Object.keys(cowGroups)[i];
|
|
2689
|
+
cowGroups[cowGroupId].minCows = cowGroupData[i].minCows;
|
|
2690
|
+
cowGroups[cowGroupId].maxCows = cowGroupData[i].maxCows;
|
|
2691
|
+
cowGroups[cowGroupId].type = cowGroupData[i].type;
|
|
2692
|
+
|
|
2693
|
+
if (cowGroupData[i].potentialCoordinates != null) {
|
|
2694
|
+
for (var j = 0; j < cowGroupData[i].potentialCoordinates.length; j++) {
|
|
2695
|
+
var cowData = {
|
|
2696
|
+
coordinates: [cowGroupData[i].potentialCoordinates[j]],
|
|
2697
|
+
group: cowGroups[cowGroupId]
|
|
2698
|
+
};
|
|
2699
|
+
new InternalCow(cowData);
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
// Trigger change listener on cow group select box to set initial min/max values
|
|
2705
|
+
$('#cow_group_select').change();
|
|
2706
|
+
|
|
2707
|
+
markCowNodes();
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2381
2710
|
// Load in block data
|
|
2382
2711
|
if(state.blocks) {
|
|
2383
2712
|
for(var i = 0; i < BLOCKS.length; i++) {
|
|
@@ -2397,21 +2726,28 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2397
2726
|
|
|
2398
2727
|
// Load in language data
|
|
2399
2728
|
var languageSelect = $('#language_select');
|
|
2400
|
-
if (state.
|
|
2729
|
+
if (state.blockly_enabled && state.python_view_enabled){
|
|
2401
2730
|
languageSelect.val('blocklyWithPythonView');
|
|
2402
|
-
} else if(state.
|
|
2731
|
+
} else if(state.blockly_enabled && state.python_enabled) {
|
|
2403
2732
|
languageSelect.val('both');
|
|
2404
|
-
} else if(state.
|
|
2733
|
+
} else if(state.python_enabled) {
|
|
2405
2734
|
languageSelect.val('python');
|
|
2406
2735
|
} else {
|
|
2407
2736
|
languageSelect.val('blockly');
|
|
2408
2737
|
}
|
|
2409
2738
|
languageSelect.change();
|
|
2410
2739
|
|
|
2740
|
+
// Load in description and hint data
|
|
2741
|
+
$('#subtitle').val(state.subtitle);
|
|
2742
|
+
$('#description').val(state.lesson);
|
|
2743
|
+
$('#hint').val(state.hint);
|
|
2744
|
+
|
|
2411
2745
|
// Other data
|
|
2412
2746
|
if(state.max_fuel) {
|
|
2413
2747
|
$('#max_fuel').val(state.max_fuel);
|
|
2414
2748
|
}
|
|
2749
|
+
|
|
2750
|
+
needsApproval = state.needs_approval;
|
|
2415
2751
|
}
|
|
2416
2752
|
|
|
2417
2753
|
function loadLevel(levelID) {
|
|
@@ -2520,10 +2856,13 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2520
2856
|
|
|
2521
2857
|
function canShare() {
|
|
2522
2858
|
if (!saveState.isSaved()) {
|
|
2523
|
-
ocargo.Drawing.startPopup(
|
|
2859
|
+
ocargo.Drawing.startPopup("Sharing", "", "Please save your level before continuing!");
|
|
2524
2860
|
return false;
|
|
2525
2861
|
} else if (hasLevelChangedSinceSave()) {
|
|
2526
|
-
ocargo.Drawing.startPopup(
|
|
2862
|
+
ocargo.Drawing.startPopup("Sharing", "", "Please save your latest changes!");
|
|
2863
|
+
return false;
|
|
2864
|
+
} else if (needsApproval) {
|
|
2865
|
+
ocargo.Drawing.startPopup("Sharing", "", "Your teacher hasn't approved your level so you can't share it yet. Please let your teacher know they need to approve it first.")
|
|
2527
2866
|
return false;
|
|
2528
2867
|
}
|
|
2529
2868
|
return true;
|
|
@@ -2586,7 +2925,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2586
2925
|
// you can copy and paste into a Django migration file
|
|
2587
2926
|
var state = extractState();
|
|
2588
2927
|
|
|
2589
|
-
var boolFields = ["
|
|
2928
|
+
var boolFields = ["python_enabled", "blockly_enabled", 'fuel_gauge'];
|
|
2590
2929
|
var stringFields = ['path', 'traffic_lights', 'cows', 'origin', 'destinations'];
|
|
2591
2930
|
var otherFields = ['max_fuel'];
|
|
2592
2931
|
|
|
@@ -2637,9 +2976,8 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2637
2976
|
if (!this.valid) {
|
|
2638
2977
|
throw "Error: cannot create actual cow from invalid internal cow!";
|
|
2639
2978
|
}
|
|
2640
|
-
|
|
2641
2979
|
// Where the cow is placed.
|
|
2642
|
-
var coordinates = this.
|
|
2980
|
+
var coordinates = this.coordinate;
|
|
2643
2981
|
var strCoordinates= {'x':coordinates.x, 'y':coordinates.y};
|
|
2644
2982
|
|
|
2645
2983
|
return { "coordinates": [strCoordinates],
|
|
@@ -2661,17 +2999,50 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2661
2999
|
|
|
2662
3000
|
};
|
|
2663
3001
|
|
|
3002
|
+
this.isOnRoad = function() {
|
|
3003
|
+
return this.coordinate && ocargo.Node.findNodeByCoordinate(this.coordinate, nodes);
|
|
3004
|
+
}
|
|
3005
|
+
|
|
3006
|
+
this.updateTheme = function() {
|
|
3007
|
+
let newType = currentTheme == THEMES.city ? ocargo.Cow.PIGEON : ocargo.Cow.WHITE;
|
|
3008
|
+
let transformDimensions = this["image"]["_"]["transform"][0]
|
|
3009
|
+
let rotateDimensions = this["image"]["_"]["transform"][1]
|
|
3010
|
+
let x = transformDimensions[1]
|
|
3011
|
+
let y = transformDimensions[2]
|
|
3012
|
+
let r = 0;
|
|
3013
|
+
if (rotateDimensions) {
|
|
3014
|
+
r = rotateDimensions[1];
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3017
|
+
this.image.remove();
|
|
3018
|
+
|
|
3019
|
+
this.image = drawing.createCowImage(newType);
|
|
3020
|
+
if (this.isOnRoad()) {
|
|
3021
|
+
let controlledNode = ocargo.Node.findNodeByCoordinate(coordinates, nodes);
|
|
3022
|
+
drawing.setCowImagePosition(this.coordinate, this.image, controlledNode);
|
|
3023
|
+
} else {
|
|
3024
|
+
this.image.transform("t" + x + "," + y + " r" + r);
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3027
|
+
setupCowListeners(this);
|
|
3028
|
+
}
|
|
3029
|
+
|
|
2664
3030
|
this.image = drawing.createCowImage(data.group.type);
|
|
2665
3031
|
this.valid = false;
|
|
2666
3032
|
|
|
2667
|
-
|
|
2668
3033
|
if ( data.coordinates && data.coordinates.length > 0 ) {
|
|
2669
|
-
|
|
2670
|
-
this.
|
|
3034
|
+
this.coordinate = new ocargo.Coordinate(data.coordinates[0].x, data.coordinates[0].y);
|
|
3035
|
+
this.valid = isValidDraggedCowPlacement(this.coordinate, this);
|
|
2671
3036
|
|
|
2672
|
-
if (this.
|
|
2673
|
-
this.
|
|
2674
|
-
drawing.setCowImagePosition(
|
|
3037
|
+
if (this.isOnRoad()) {
|
|
3038
|
+
const controlledNode = ocargo.Node.findNodeByCoordinate(this.coordinate, nodes);
|
|
3039
|
+
drawing.setCowImagePosition(this.coordinate, this.image, controlledNode);
|
|
3040
|
+
} else {
|
|
3041
|
+
const box = this.image.getBBox();
|
|
3042
|
+
// calculate position of the image
|
|
3043
|
+
const paperX = (this.coordinate.x + 1) * GRID_SPACE_SIZE - box.width/2;
|
|
3044
|
+
const paperY = (GRID_HEIGHT - this.coordinate.y) * GRID_SPACE_SIZE - box.height/2;
|
|
3045
|
+
this.image.transform('t' + paperX + ',' + paperY );
|
|
2675
3046
|
}
|
|
2676
3047
|
} else {
|
|
2677
3048
|
this.image.transform('...t' + (-paper.scrollLeft()) + ',' + paper.scrollTop());
|
|
@@ -2679,6 +3050,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2679
3050
|
|
|
2680
3051
|
setupCowListeners(this);
|
|
2681
3052
|
this.image.attr({'cursor':'pointer'});
|
|
3053
|
+
this.image.attr({'position': 'absolute'});
|
|
2682
3054
|
cows.push(this);
|
|
2683
3055
|
|
|
2684
3056
|
}
|
|
@@ -2808,7 +3180,7 @@ ocargo.LevelEditor = function(levelId) {
|
|
|
2808
3180
|
/******************/
|
|
2809
3181
|
|
|
2810
3182
|
$(function() {
|
|
2811
|
-
|
|
3183
|
+
new ocargo.LevelEditor(LEVEL);
|
|
2812
3184
|
var subtitle = interpolate(
|
|
2813
3185
|
gettext('Click %(help_icon)s%(help_label)s for clues on getting started.'), {
|
|
2814
3186
|
help_icon: ocargo.jsElements.image(ocargo.Drawing.imageDir + 'icons/help.svg', 'popupHelp'),
|
|
@@ -2821,7 +3193,7 @@ $(function() {
|
|
|
2821
3193
|
} else {
|
|
2822
3194
|
let buttons = '';
|
|
2823
3195
|
buttons += ocargo.button.dismissButtonHtml("edit_button", "Edit");
|
|
2824
|
-
buttons += ocargo.button.redirectButtonHtml("play_button", Urls.levels() + "custom/" + LEVEL,"Play");
|
|
3196
|
+
buttons += ocargo.button.redirectButtonHtml("play_button", Urls.levels() + "custom/" + LEVEL, "Play");
|
|
2825
3197
|
|
|
2826
3198
|
ocargo.Drawing.startPopup(
|
|
2827
3199
|
gettext('Welcome back!'),
|