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.
Files changed (170) hide show
  1. example_project/rapid_router_test_settings.py +19 -7
  2. example_project/settings.py +21 -8
  3. example_project/urls.py +5 -6
  4. game/__init__.py +1 -1
  5. game/admin.py +7 -2
  6. game/character.py +8 -0
  7. game/decor.py +40 -0
  8. game/end_to_end_tests/base_game_test.py +34 -27
  9. game/end_to_end_tests/editor_page.py +15 -0
  10. game/end_to_end_tests/game_page.py +88 -20
  11. game/end_to_end_tests/selenium_test_case.py +1 -20
  12. game/end_to_end_tests/test_cow_crashes.py +3 -5
  13. game/end_to_end_tests/test_level_editor.py +273 -10
  14. game/end_to_end_tests/test_level_selection.py +25 -3
  15. game/end_to_end_tests/test_play_through.py +222 -127
  16. game/end_to_end_tests/test_python_levels.py +41 -7
  17. game/end_to_end_tests/test_saving_workspace.py +2 -1
  18. game/forms.py +7 -1
  19. game/level_management.py +26 -11
  20. game/messages.py +899 -337
  21. game/migrations/0001_squashed_0025_levels_ordering_pt1.py +19 -1
  22. game/migrations/0026_levels_pt2.py +13 -2
  23. game/migrations/0032_cannot_turn_left_level.py +13 -2
  24. game/migrations/0033_recursion_level.py +13 -2
  25. game/migrations/0034_joes_level.py +13 -2
  26. game/migrations/0035_disable_route_score_level_70.py +0 -2
  27. game/migrations/0036_level_score_73.py +0 -2
  28. game/migrations/0037_level_score_79.py +0 -2
  29. game/migrations/0038_level_score_40.py +0 -1
  30. game/migrations/0042_level_score_73.py +0 -2
  31. game/migrations/0048_add_cow_field_and_blocks.py +0 -2
  32. game/migrations/0049_level_score_34.py +0 -2
  33. game/migrations/0050_level_score_40.py +0 -2
  34. game/migrations/0051_level_score_49.py +0 -1
  35. game/migrations/0086_loop_levels.py +13 -2
  36. game/migrations/0092_disable_algo_score_in_custom_levels.py +28 -0
  37. game/migrations/0093_alter_level_character_name.py +18 -0
  38. game/migrations/0094_add_hint_lesson_subtitle_to_levels.py +28 -0
  39. game/migrations/0095_level_commands.py +18 -0
  40. game/migrations/0096_alter_level_commands.py +18 -0
  41. game/migrations/0097_add_python_den_levels.py +1515 -0
  42. game/migrations/0098_add_episode_link_fields.py +44 -0
  43. game/migrations/0099_python_episodes_links.py +103 -0
  44. game/migrations/0100_reorder_python_levels.py +179 -0
  45. game/migrations/0101_rename_episodes.py +45 -0
  46. game/migrations/0102_reoder_episodes_13_14.py +136 -0
  47. game/migrations/0103_level_1015_solution.py +26 -0
  48. game/migrations/0104_remove_level_direct_drive.py +17 -0
  49. game/migrations/0105_delete_invalid_attempts.py +18 -0
  50. game/migrations/0106_fields_to_snake_case.py +48 -0
  51. game/migrations/0107_rename_worksheet_link_episode_student_worksheet_link.py +18 -0
  52. game/migrations/0108_episode_indy_worksheet_link.py +18 -0
  53. game/migrations/0109_create_episodes_23_and_24.py +99 -0
  54. game/migrations/0110_remove_episode_indy_worksheet_link_and_more.py +100 -0
  55. game/migrations/0111_create_worksheets.py +149 -0
  56. game/migrations/0112_worksheet_locked_classes.py +21 -0
  57. game/migrations/0113_level_needs_approval.py +18 -0
  58. game/migrations/0114_default_and_non_student_levels_no_approval.py +31 -0
  59. game/migrations/0115_level_level__default_does_not_need_approval.py +22 -0
  60. game/migrations/0116_update_worksheet_video_links.py +68 -0
  61. game/migrations/0117_update_solutions_to_if_else.py +61 -0
  62. game/models.py +127 -17
  63. game/permissions.py +51 -19
  64. game/python_den_urls.py +26 -0
  65. game/random_road.py +9 -9
  66. game/serializers.py +12 -17
  67. game/static/django_reverse_js/js/reverse.js +171 -0
  68. game/static/game/css/LilitaOne-Regular.ttf +0 -0
  69. game/static/game/css/backgrounds.css +8 -12
  70. game/static/game/css/dataTables.custom.css +3 -2
  71. game/static/game/css/editor.css +47 -0
  72. game/static/game/css/game.css +37 -43
  73. game/static/game/css/game_screen.css +16 -0
  74. game/static/game/css/level_editor.css +5 -0
  75. game/static/game/css/level_selection.css +17 -2
  76. game/static/game/image/Python_Den_hero_student.png +0 -0
  77. game/static/game/image/Python_levels_page.svg +1954 -0
  78. game/static/game/image/characters/front_view/Electric_van.svg +448 -0
  79. game/static/game/image/characters/top_view/Electric_van.svg +448 -0
  80. game/static/game/image/decor/city/solar_panel.svg +1200 -0
  81. game/static/game/image/decor/farm/solar_panel.svg +86 -0
  82. game/static/game/image/decor/grass/solar_panel.svg +86 -0
  83. game/static/game/image/decor/snow/solar_panel.svg +173 -0
  84. game/static/game/image/electric_van.svg +448 -0
  85. game/static/game/image/icons/description.svg +1 -0
  86. game/static/game/image/icons/hint.svg +1 -0
  87. game/static/game/image/icons/python.svg +1 -1
  88. game/static/game/image/pigeon.svg +684 -0
  89. game/static/game/image/python_den_header.svg +19 -0
  90. game/static/game/js/animation.js +65 -24
  91. game/static/game/js/blockly/msg/js/bg.js +52 -1
  92. game/static/game/js/blockly/msg/js/ca.js +52 -1
  93. game/static/game/js/blockly/msg/js/en-gb.js +2 -0
  94. game/static/game/js/blockly/msg/js/en.js +2 -0
  95. game/static/game/js/blockly/msg/js/es.js +52 -1
  96. game/static/game/js/blockly/msg/js/fr.js +2 -0
  97. game/static/game/js/blockly/msg/js/hi.js +2 -0
  98. game/static/game/js/blockly/msg/js/it.js +52 -1
  99. game/static/game/js/blockly/msg/js/pl.js +52 -1
  100. game/static/game/js/blockly/msg/js/pt-br.js +52 -1
  101. game/static/game/js/blockly/msg/js/ru.js +52 -1
  102. game/static/game/js/blockly/msg/js/ur.js +52 -1
  103. game/static/game/js/blocklyCustomBlocks.js +93 -52
  104. game/static/game/js/button.js +12 -0
  105. game/static/game/js/cow.js +11 -7
  106. game/static/game/js/drawing.js +68 -29
  107. game/static/game/js/editor.js +23 -0
  108. game/static/game/js/game.js +74 -110
  109. game/static/game/js/level_editor.js +646 -274
  110. game/static/game/js/level_moderation.js +33 -2
  111. game/static/game/js/level_selection.js +1 -1
  112. game/static/game/js/loadLanguages.js +2 -2
  113. game/static/game/js/model.js +32 -2
  114. game/static/game/js/pythonControl.js +14 -1
  115. game/static/game/js/scoreboard.js +0 -37
  116. game/static/game/js/scoreboardSharedLevels.js +48 -0
  117. game/static/game/js/skulpt/skulpt-stdlib.js +1 -1
  118. game/static/game/js/sound.js +52 -5
  119. game/static/game/raphael_image/characters/top_view/Electric_van.svg +448 -0
  120. game/static/game/raphael_image/decor/city/solar_panel.svg +1200 -0
  121. game/static/game/raphael_image/decor/farm/solar_panel.svg +86 -0
  122. game/static/game/raphael_image/decor/grass/solar_panel.svg +86 -0
  123. game/static/game/raphael_image/decor/snow/solar_panel.svg +173 -0
  124. game/static/game/raphael_image/pigeon.svg +685 -0
  125. game/static/game/sass/game.scss +2 -2
  126. game/static/game/sound/clown_horn.mp3 +0 -0
  127. game/static/game/sound/clown_horn.ogg +0 -0
  128. game/static/game/sound/electric_van_starting.mp3 +0 -0
  129. game/static/game/sound/electric_van_starting.ogg +0 -0
  130. game/static/game/sound/pigeon.mp3 +0 -0
  131. game/static/game/sound/pigeon.ogg +0 -0
  132. game/static/game/sound/sleigh_bells.mp3 +0 -0
  133. game/static/game/sound/sleigh_bells.ogg +0 -0
  134. game/static/game/sound/sleigh_crash.mp3 +0 -0
  135. game/static/game/sound/sleigh_crash.ogg +0 -0
  136. game/templates/game/base.html +34 -14
  137. game/templates/game/basenonav.html +11 -5
  138. game/templates/game/game.html +142 -38
  139. game/templates/game/level_editor.html +340 -236
  140. game/templates/game/level_moderation.html +19 -6
  141. game/templates/game/level_selection.html +18 -110
  142. game/templates/game/python_den_level_selection.html +291 -0
  143. game/templates/game/python_den_worksheet.html +101 -0
  144. game/templates/game/scoreboard.html +83 -64
  145. game/tests/test_level_editor.py +94 -26
  146. game/tests/test_level_selection.py +149 -46
  147. game/tests/test_python_den_worksheet.py +85 -0
  148. game/tests/test_scoreboard.py +34 -7
  149. game/tests/utils/level.py +32 -26
  150. game/theme.py +5 -5
  151. game/urls.py +199 -61
  152. game/views/language_code_conversions.py +86 -86
  153. game/views/level.py +155 -63
  154. game/views/level_editor.py +88 -55
  155. game/views/level_moderation.py +23 -0
  156. game/views/level_selection.py +116 -47
  157. game/views/level_solutions.py +491 -106
  158. game/views/scoreboard.py +76 -51
  159. game/views/worksheet.py +25 -0
  160. rapid_router-7.6.8.dist-info/METADATA +174 -0
  161. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/RECORD +164 -104
  162. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/WHEEL +1 -1
  163. example_project/manage.py +0 -10
  164. game/static/game/image/actions/go.svg +0 -18
  165. game/static/game/js/js-reverse.js +0 -14
  166. game/static/game/js/pqselect.min.js +0 -9
  167. game/static/game/js/widget-scroller.js +0 -906
  168. rapid_router-5.18.0.dist-info/METADATA +0 -17
  169. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info/licenses}/LICENSE.md +0 -0
  170. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/top_level.txt +0 -0
@@ -433,4 +433,55 @@ Blockly.Msg["VARIABLES_HUE"] = "330";
433
433
  Blockly.Msg["TEXTS_HUE"] = "160";
434
434
  Blockly.Msg["PROCEDURES_HUE"] = "290";
435
435
  Blockly.Msg["COLOUR_HUE"] = "20";
436
- Blockly.Msg["VARIABLES_DYNAMIC_HUE"] = "310";
436
+ Blockly.Msg["VARIABLES_DYNAMIC_HUE"] = "310";
437
+
438
+ Blockly.Msg["START_TITLE"] = "Начало";
439
+ Blockly.Msg["START_TOOLTIP"] = "Начало программы"
440
+ Blockly.Msg["MOVE_FORWARDS_TITLE"] = "Ехать вперед";
441
+ Blockly.Msg["MOVE_FORWARDS_TOOLTIP"] = "переместить грузовик вперед";
442
+ Blockly.Msg["TURN_LEFT_TITLE"] = "Повернуть налево";
443
+ Blockly.Msg["TURN_LEFT_TOOLTIP"] = "повернуть грузовик налево";
444
+ Blockly.Msg["TURN_RIGHT_TITLE"] = "Повернуть направо";
445
+ Blockly.Msg["TURN_RIGHT_TOOLTIP"] = "повернуть грузовик направо";
446
+ Blockly.Msg["TURN_AROUND_TITLE"] = "Развернуться";
447
+ Blockly.Msg["TURN_AROUND_TOOLTIP"] = "развернуть грузови";
448
+
449
+ Blockly.Msg["WAIT_TITLE"] = "Подождать";
450
+ Blockly.Msg["WAIT_TOOLTIP"] = "оставить грузовик на месте";
451
+ Blockly.Msg["DELIVER_TITLE"] = "Доставить";
452
+ Blockly.Msg["DELIVER_TOOLTIP"] = "доставить товары из грузовика";
453
+ Blockly.Msg["SOUND_HORN_TITLE"] = "Подать сигнал";
454
+ Blockly.Msg["SOUND_HORN_TOOLTIP"] = "просигналить, чтобы спугнуть коров";
455
+
456
+ Blockly.Msg["ROAD_EXISTS_FORWARD_TITLE"] = "Есть путь впереди";
457
+ Blockly.Msg["ROAD_EXISTS_LEFT_TITLE"] = "Есть путь слева";
458
+ Blockly.Msg["ROAD_EXISTS_RIGHT_TITLE"] = "Есть путь справа";
459
+ Blockly.Msg["TRAFFIC_LIGHT_RED_TITLE"] = "Светофор красный";
460
+ Blockly.Msg["TRAFFIC_LIGHT_GREEN_TITLE"] = "Светофор зеленый";
461
+ Blockly.Msg["DEAD_END_TITLE"] = "Тупик";
462
+ Blockly.Msg["AT_DESTINATION_TITLE"] = "В пункте назначения";
463
+ Blockly.Msg["COW_CROSSING_TITLE"] = "Коровы";
464
+ Blockly.Msg["PIGEON_CROSSING_TITLE"] = "Голуби";
465
+
466
+ Blockly.Msg["CALL_PROC_TITLE"] = "Вызвать";
467
+ Blockly.Msg["CALL_PROC_TOOLTIP"] = "вызывает процедуру";
468
+ Blockly.Msg["DECLARE_PROC_TITLE"] = "Определить";
469
+ Blockly.Msg["DECLARE_PROC_SUBTITLE"] = "выполнять";
470
+ Blockly.Msg["DECLARE_PROC_TOOLTIP"] = "определяет процедуру";
471
+ Blockly.Msg["CONTROLS_REPEAT_WHILE_TITLE"] = "Повторять пока";
472
+ Blockly.Msg["CONTROLS_REPEAT_WHILE_SUBTITLE"] = "выполнять";
473
+ Blockly.Msg["CONTROLS_REPEAT_WHILE_TOOLTIP"] = "пока значение истинно, выполнять инструкции";
474
+ Blockly.Msg["CONTROLS_REPEAT_UNTIL_TITLE"] = "Повторять до тех пор, пока";
475
+ Blockly.Msg["CONTROLS_REPEAT_UNTIL_SUBTITLE"] = "выполнять";
476
+ Blockly.Msg["CONTROLS_REPEAT_UNTIL_TOOLTIP"] = "выполнять инструкции до тех пор, пока";
477
+
478
+ Blockly.Msg["VARIABLES_GET_TOOLTIP"] = "переменная";
479
+ Blockly.Msg["VARIABLES_SET_TITLE"] = "Присвоить";
480
+ Blockly.Msg["VARIABLES_SET_SUBTITLE"] = "значение";
481
+ Blockly.Msg["VARIABLES_SET_TOOLTIP"] = "присвоить переменной значение";
482
+ Blockly.Msg["VARIABLES_NUMERIC_SET_TOOLTIP"] = "присвоить переменной число";
483
+ Blockly.Msg["VARIABLES_INCREMENT_TITLE"] = "Увеличить";
484
+ Blockly.Msg["VARIABLES_INCREMENT_SUBTITLE"] = "на";
485
+ Blockly.Msg["VARIABLES_INCREMENT_TOOLTIP"] = "увеличить переменную";
486
+ Blockly.Msg["NUMBER_TITLE"] = "Число";
487
+ Blockly.Msg["NUMBER_TOOLTIP"] = "число";
@@ -433,4 +433,55 @@ Blockly.Msg["VARIABLES_HUE"] = "330";
433
433
  Blockly.Msg["TEXTS_HUE"] = "160";
434
434
  Blockly.Msg["PROCEDURES_HUE"] = "290";
435
435
  Blockly.Msg["COLOUR_HUE"] = "20";
436
- Blockly.Msg["VARIABLES_DYNAMIC_HUE"] = "310";
436
+ Blockly.Msg["VARIABLES_DYNAMIC_HUE"] = "310";
437
+
438
+ Blockly.Msg["START_TITLE"] = "شروع کریں";
439
+ Blockly.Msg["START_TOOLTIP"] = "پروگرام کا آغاز"
440
+ Blockly.Msg["MOVE_FORWARDS_TITLE"] = "آگے بڑھیں";
441
+ Blockly.Msg["MOVE_FORWARDS_TOOLTIP"] = "وین کو آگے بڑھائیں";
442
+ Blockly.Msg["TURN_LEFT_TITLE"] = "بائیں مڑیں";
443
+ Blockly.Msg["TURN_LEFT_TOOLTIP"] = "وین بائیں مڑیں";
444
+ Blockly.Msg["TURN_RIGHT_TITLE"] = "دائیں مڑیں";
445
+ Blockly.Msg["TURN_RIGHT_TOOLTIP"] = "وین کو دائیں مڑیں";
446
+ Blockly.Msg["TURN_AROUND_TITLE"] = "مڑیں";
447
+ Blockly.Msg["TURN_AROUND_TOOLTIP"] = "وین کو گھمایں";
448
+
449
+ Blockly.Msg["WAIT_TITLE"] = "انتظار کریں";
450
+ Blockly.Msg["WAIT_TOOLTIP"] = "وین کو روکے رکھیں";
451
+ Blockly.Msg["DELIVER_TITLE"] = "سامان پہنچایں";
452
+ Blockly.Msg["DELIVER_TOOLTIP"] = "وین سے سامان پہنچایں";
453
+ Blockly.Msg["SOUND_HORN_TITLE"] = "ہارن بجایں";
454
+ Blockly.Msg["SOUND_HORN_TOOLTIP"] = "گائے بھینسوں";
455
+
456
+ Blockly.Msg["ROAD_EXISTS_FORWARD_TITLE"] = ""; // ?
457
+ Blockly.Msg["ROAD_EXISTS_LEFT_TITLE"] = ""; // ?
458
+ Blockly.Msg["ROAD_EXISTS_RIGHT_TITLE"] = ""; // ?
459
+ Blockly.Msg["TRAFFIC_LIGHT_RED_TITLE"] = ""; // ?
460
+ Blockly.Msg["TRAFFIC_LIGHT_GREEN_TITLE"] = ""; // ?
461
+ Blockly.Msg["DEAD_END_TITLE"] = "ٹریفک لائٹ سرخ/سبز";
462
+ Blockly.Msg["AT_DESTINATION_TITLE"] = "آگے راستہ بند ہے";
463
+ Blockly.Msg["COW_CROSSING_TITLE"] = "منزل پر پہنچ گئے";
464
+ Blockly.Msg["PIGEON_CROSSING_TITLE"] = ""; // untranslated
465
+
466
+ Blockly.Msg["CALL_PROC_TITLE"] = ""; // ?
467
+ Blockly.Msg["CALL_PROC_TOOLTIP"] = ""; // ?
468
+ Blockly.Msg["DECLARE_PROC_TITLE"] = "";
469
+ Blockly.Msg["DECLARE_PROC_SUBTITLE"] = ""; // ?
470
+ Blockly.Msg["DECLARE_PROC_TOOLTIP"] = ""; // ?
471
+ Blockly.Msg["CONTROLS_REPEAT_WHILE_TITLE"] = ""; // ?
472
+ Blockly.Msg["CONTROLS_REPEAT_WHILE_SUBTITLE"] = ""; // ?
473
+ Blockly.Msg["CONTROLS_REPEAT_WHILE_TOOLTIP"] = ""; // ?
474
+ Blockly.Msg["CONTROLS_REPEAT_UNTIL_TITLE"] = ""; // ?
475
+ Blockly.Msg["CONTROLS_REPEAT_UNTIL_SUBTITLE"] = ""; // ?
476
+ Blockly.Msg["CONTROLS_REPEAT_UNTIL_TOOLTIP"] = ""; // ?
477
+
478
+ Blockly.Msg["VARIABLES_GET_TOOLTIP"] = ""; // ?
479
+ Blockly.Msg["VARIABLES_SET_TITLE"] = ""; // ?
480
+ Blockly.Msg["VARIABLES_SET_SUBTITLE"] = ""; // ?
481
+ Blockly.Msg["VARIABLES_SET_TOOLTIP"] = ""; // ?
482
+ Blockly.Msg["VARIABLES_NUMERIC_SET_TOOLTIP"] = ""; // ?
483
+ Blockly.Msg["VARIABLES_INCREMENT_TITLE"] = ""; // ?
484
+ Blockly.Msg["VARIABLES_INCREMENT_SUBTITLE"] = ""; // ?
485
+ Blockly.Msg["VARIABLES_INCREMENT_TOOLTIP"] = ""; // ?
486
+ Blockly.Msg["NUMBER_TITLE"] = ""; // ?
487
+ Blockly.Msg["NUMBER_TOOLTIP"] = ""; // ?
@@ -16,14 +16,15 @@ function initCustomBlocksDescription() {
16
16
  this.setColour(50);
17
17
  this.appendDummyInput()
18
18
  .appendField(Blockly.Msg.START_TITLE)
19
- .appendField(new Blockly.FieldImage(
20
- new Date().getMonth() === 11 && CHARACTER_NAME === "Van"
21
- ? ocargo.Drawing.imageDir + "characters/top_view/Sleigh.svg"
22
- : ocargo.Drawing.imageDir + CHARACTER_EN_FACE_URL,
23
- ocargo.BlocklyControl.BLOCK_CHARACTER_HEIGHT,
24
- ocargo.BlocklyControl.BLOCK_CHARACTER_WIDTH
25
- )
26
- );
19
+ .appendField(
20
+ new Blockly.FieldImage(
21
+ new Date().getMonth() === 11 && CHARACTER_NAME === "Van"
22
+ ? ocargo.Drawing.imageDir + "characters/top_view/Sleigh.svg"
23
+ : ocargo.Drawing.imageDir + CHARACTER_EN_FACE_URL,
24
+ ocargo.BlocklyControl.BLOCK_CHARACTER_HEIGHT,
25
+ ocargo.BlocklyControl.BLOCK_CHARACTER_WIDTH
26
+ )
27
+ );
27
28
  this.setNextStatement(true, "Action");
28
29
  this.setTooltip(Blockly.Msg.START_TOOLTIP);
29
30
  this.setDeletable(false);
@@ -183,22 +184,30 @@ function initCustomBlocksDescription() {
183
184
  },
184
185
  };
185
186
 
186
- Blockly.Blocks['sound_horn'] = {
187
- init: function() {
188
- this.setColour(160);
189
- this.appendDummyInput()
190
- .appendField(Blockly.Msg.SOUND_HORN_TITLE)
191
- .appendField(new Blockly.FieldImage(ocargo.Drawing.imageDir + 'empty.svg',
192
- 43,
193
- ocargo.BlocklyControl.BLOCK_HEIGHT))
194
- .appendField(new Blockly.FieldImage(ocargo.Drawing.imageDir + 'empty.svg',
195
- ocargo.BlocklyControl.IMAGE_WIDTH,
196
- ocargo.BlocklyControl.BLOCK_HEIGHT));
197
- this.setPreviousStatement(true, 'Action');
198
- this.setNextStatement(true, 'Action');
199
- this.setTooltip(Blockly.Msg.SOUND_HORN_TOOLTIP);
200
- }
201
- };
187
+ Blockly.Blocks["sound_horn"] = {
188
+ init: function () {
189
+ this.setColour(160);
190
+ this.appendDummyInput()
191
+ .appendField(Blockly.Msg.SOUND_HORN_TITLE)
192
+ .appendField(
193
+ new Blockly.FieldImage(
194
+ ocargo.Drawing.imageDir + "empty.svg",
195
+ 43,
196
+ ocargo.BlocklyControl.BLOCK_HEIGHT
197
+ )
198
+ )
199
+ .appendField(
200
+ new Blockly.FieldImage(
201
+ ocargo.Drawing.imageDir + "empty.svg",
202
+ ocargo.BlocklyControl.IMAGE_WIDTH,
203
+ ocargo.BlocklyControl.BLOCK_HEIGHT
204
+ )
205
+ );
206
+ this.setPreviousStatement(true, "Action");
207
+ this.setNextStatement(true, "Action");
208
+ this.setTooltip(Blockly.Msg.SOUND_HORN_TOOLTIP);
209
+ },
210
+ };
202
211
 
203
212
  /*****************/
204
213
  /* Conditions */
@@ -277,20 +286,50 @@ function initCustomBlocksDescription() {
277
286
  },
278
287
  };
279
288
 
280
- Blockly.Blocks['cow_crossing'] = {
281
- init: function() {
282
- this.setColour(210);
283
- this.setOutput(true, 'Boolean');
284
- this.appendDummyInput()
285
- .appendField(Blockly.Msg.COW_CROSSING_TITLE)
286
- .appendField(new Blockly.FieldImage(ocargo.Drawing.imageDir + ocargo.Drawing.whiteCowUrl,
287
- ocargo.BlocklyControl.COW_WIDTH,
288
- ocargo.BlocklyControl.BLOCK_HEIGHT), 'IMAGE');
289
- }
290
- };
291
- /****************/
292
- /* Procedures */
293
- /****************/
289
+ Blockly.Blocks["cow_crossing"] = {
290
+ init: function () {
291
+ this.setColour(210);
292
+ this.setOutput(true, "Boolean");
293
+ let imageUrl =
294
+ ocargo.Drawing.animalType == ocargo.Cow.PIGEON
295
+ ? ocargo.Drawing.pigeonUrl
296
+ : ocargo.Drawing.whiteCowUrl;
297
+ this.appendDummyInput()
298
+ .appendField(
299
+ ocargo.Drawing.animalType == ocargo.Cow.PIGEON
300
+ ? Blockly.Msg.PIGEON_CROSSING_TITLE
301
+ : Blockly.Msg.COW_CROSSING_TITLE
302
+ )
303
+ .appendField(
304
+ new Blockly.FieldImage(
305
+ ocargo.Drawing.imageDir + imageUrl,
306
+ ocargo.BlocklyControl.COW_WIDTH,
307
+ ocargo.BlocklyControl.BLOCK_HEIGHT
308
+ ),
309
+ "IMAGE"
310
+ );
311
+ },
312
+ };
313
+
314
+ Blockly.Blocks["pigeon_crossing_IMAGE_ONLY"] = {
315
+ init: function () {
316
+ this.setColour(210);
317
+ this.setOutput(true, "Boolean");
318
+ this.appendDummyInput()
319
+ .appendField("pigeons")
320
+ .appendField(
321
+ new Blockly.FieldImage(
322
+ ocargo.Drawing.imageDir + ocargo.Drawing.pigeonUrl,
323
+ ocargo.BlocklyControl.COW_WIDTH,
324
+ ocargo.BlocklyControl.BLOCK_HEIGHT
325
+ ),
326
+ "IMAGE"
327
+ );
328
+ },
329
+ };
330
+ /****************/
331
+ /* Procedures */
332
+ /****************/
294
333
 
295
334
  Blockly.Blocks["call_proc"] = {
296
335
  // Block for calling a defined procedure
@@ -323,7 +362,7 @@ function initCustomBlocksDescription() {
323
362
  .appendField(new Blockly.FieldTextInput(name), "NAME");
324
363
  this.appendStatementInput("DO")
325
364
  .setCheck("Action")
326
- .appendField(gettext("Do"));
365
+ .appendField(Blockly.Msg.DECLARE_PROC_SUBTITLE);
327
366
  this.setTooltip(Blockly.Msg.DECLARE_PROC_TOOLTIP);
328
367
  this.statementConnection_ = null;
329
368
  },
@@ -546,22 +585,21 @@ function initCustomBlocksPython() {
546
585
  return "my_van.wait()\n";
547
586
  };
548
587
 
549
- Blockly.Python['deliver'] = function(block) {
550
- return 'my_van.deliver()\n';
551
- };
552
-
553
- Blockly.Python['sound_horn'] = function(block) {
554
- return 'my_van.sound_horn()\n';
555
- };
588
+ Blockly.Python["deliver"] = function (block) {
589
+ return "my_van.deliver()\n";
590
+ };
556
591
 
592
+ Blockly.Python["sound_horn"] = function (block) {
593
+ return "my_van.sound_horn()\n";
594
+ };
557
595
 
558
596
  Blockly.Python["road_exists"] = function (block) {
559
597
  if (block.inputList[0].fieldRow[1].value_ === "FORWARD") {
560
- var python = "my_van.is_road('FORWARD')";
598
+ var python = "my_van.is_road_forward()";
561
599
  } else if (block.inputList[0].fieldRow[1].value_ === "LEFT") {
562
- var python = "my_van.is_road('LEFT')";
600
+ var python = "my_van.is_road_left()";
563
601
  } else {
564
- var python = "my_van.is_road('RIGHT')";
602
+ var python = "my_van.is_road_right()";
565
603
  }
566
604
 
567
605
  return [python, Blockly.Python.ORDER_NONE];
@@ -571,9 +609,9 @@ function initCustomBlocksPython() {
571
609
  Blockly.Python["traffic_light"] = function (block) {
572
610
  var python;
573
611
  if (block.inputList[0].fieldRow[1].value_ === ocargo.TrafficLight.RED) {
574
- python = "my_van.at_traffic_light('RED')";
612
+ python = "my_van.is_red_traffic_light()";
575
613
  } else {
576
- python = "my_van.at_traffic_light('GREEN')";
614
+ python = "my_van.is_green_traffic_light()";
577
615
  }
578
616
 
579
617
  return [python, Blockly.Python.ORDER_NONE]; //TODO: figure out what this ordering relates to
@@ -585,7 +623,7 @@ function initCustomBlocksPython() {
585
623
  };
586
624
 
587
625
  Blockly.Python["cow_crossing"] = function (block) {
588
- return ["my_van.cow_crossing()", Blockly.Python.ORDER_NONE];
626
+ return ["my_van.is_animal_crossing()", Blockly.Python.ORDER_NONE];
589
627
  // TODO: figure out what this ordering relates to
590
628
  };
591
629
 
@@ -615,6 +653,9 @@ function initCustomBlocksPython() {
615
653
  "condition",
616
654
  Blockly.Python.ORDER_ATOMIC
617
655
  );
656
+
657
+ condition = condition.replace(/\((.*)\)/, "$1");
658
+
618
659
  var subBlock = Blockly.Python.statementToCode(block, "body");
619
660
  var code = "while " + condition + ":\n" + subBlock;
620
661
  return code;
@@ -14,6 +14,18 @@ ocargo.button.redirectButtonHtml = function(id, location, label){
14
14
  return Handlebars.templates['button-redirect']({id: id, location: location, label: label});
15
15
  };
16
16
 
17
+ // Returns the html code for a button which redirects to a given episode on the level selection page
18
+ ocargo.button.episodeRedirectButtonHtml = function(id, location, label, next_episode){
19
+ return `<button id="${id}" class="navigation_button long_button"
20
+ onclick="function onClick() {
21
+ window.location.href='${location}';
22
+ localStorage.setItem('currentEpisode', '${next_episode}');
23
+ };
24
+ onClick()">
25
+ <span>${label}</span>
26
+ </button>`
27
+ }
28
+
17
29
  // Returns the html code for a button which shows the try again message and closes the popup
18
30
  ocargo.button.tryAgainButtonHtml = function(){
19
31
  return ocargo.button.dismissButtonHtml('try_again_button', gettext('Try again'));
@@ -8,12 +8,15 @@ ocargo.Cow = function(id, data, nodes) {
8
8
  this.type = data.type;
9
9
  this.potentialNodes = []; // Potential nodes at which a cow could appear
10
10
  this.activeNodes = {}; // Actual nodes at which cows will appear during a run.
11
+ this.coordinates = []; // coordinates of the cows, some cows may have null nodes that denotes they are outside of road
12
+
11
13
  for(var i = 0; i < data.potentialCoordinates.length; i++) {
12
14
  var coordinate = new ocargo.Coordinate(data.potentialCoordinates[i].x, data.potentialCoordinates[i].y);
13
- var node = ocargo.Node.findNodeByCoordinate(coordinate, nodes)
14
- this.potentialNodes.push(ocargo.Node.findNodeByCoordinate(coordinate, nodes));
15
- var coordinate_str = JSON.stringify(node.coordinate)
16
- this.activeNodes[coordinate_str] = ocargo.Cow.ACTIVE
15
+ var node = ocargo.Node.findNodeByCoordinate(coordinate, nodes);
16
+ this.potentialNodes.push(node);
17
+ var coordinate_str = JSON.stringify(coordinate);
18
+ this.activeNodes[coordinate_str] = ocargo.Cow.ACTIVE;
19
+ this.coordinates.push(coordinate);
17
20
  }
18
21
  };
19
22
  ocargo.Cow.prototype.reset = function() {
@@ -26,14 +29,14 @@ ocargo.Cow.prototype.reset = function() {
26
29
  ocargo.Cow.prototype.queueLeaveAnimation = function(model, node) {
27
30
  ocargo.animation.appendAnimation({
28
31
  type: 'callable',
29
- functionCall: ocargo.sound.cow,
30
- description: 'cow sound'
32
+ functionCall: this.type == ocargo.Cow.PIGEON ? ocargo.sound.pigeon : ocargo.sound.cow,
33
+ description: 'animal sound'
31
34
  });
32
35
  ocargo.animation.appendAnimation({
33
36
  type: 'cow_leave',
34
37
  id: this.id,
35
38
  coordinate: node.coordinate,
36
- description: 'Cow leaving'
39
+ description: 'animal leaving'
37
40
  });
38
41
  };
39
42
 
@@ -49,3 +52,4 @@ ocargo.Cow.ACTIVE = 'ACTIVE';
49
52
  ocargo.Cow.INACTIVE = 'INACTIVE';
50
53
  ocargo.Cow.WHITE = 'WHITE';
51
54
  ocargo.Cow.BROWN = 'BROWN';
55
+ ocargo.Cow.PIGEON = 'PIGEON';
@@ -10,12 +10,15 @@ let PAPER_HEIGHT = GRID_SPACE_SIZE * GRID_HEIGHT
10
10
  let PAPER_PADDING = 30
11
11
  let EXTENDED_PAPER_WIDTH = PAPER_WIDTH + 2 * PAPER_PADDING
12
12
  let EXTENDED_PAPER_HEIGHT = PAPER_WIDTH + 2 * PAPER_PADDING
13
+ let SEMI_EXTENDED_PAPER_HEIGHT = PAPER_HEIGHT + 2 * PAPER_PADDING
13
14
 
14
15
  let DEFAULT_CHARACTER_WIDTH = 40
15
16
  let DEFAULT_CHARACTER_HEIGHT = 20
16
17
 
17
18
  let COW_WIDTH = 80
18
19
  let COW_HEIGHT = 80
20
+ const TRAFFIC_LIGHT_WIDTH = 30
21
+ const TRAFFIC_LIGHT_HEIGHT = 80
19
22
 
20
23
  let zoom = 15
21
24
 
@@ -454,7 +457,7 @@ ocargo.Drawing = function (startingPosition) {
454
457
 
455
458
  let path = ocargo.Drawing.raphaelImageDir + 'road_tiles/'
456
459
 
457
- path += CHARACTER_NAME === 'Van' ? 'road/' : 'path/'
460
+ path += (CHARACTER_NAME === 'Van' || CHARACTER_NAME === "Electric van") ? 'road/' : 'path/'
458
461
 
459
462
  roadImages = []
460
463
  for (let i = 0; i < nodes.length; i++) {
@@ -750,8 +753,11 @@ ocargo.Drawing = function (startingPosition) {
750
753
  let xOffset = 0
751
754
  let yOffset = 0
752
755
  let rotation = 0
753
-
754
- if (node.connectedNodes.length === 1) {
756
+ if (node == null) {
757
+ // the cow is outside of road
758
+ rotation = 0
759
+ }
760
+ else if (node.connectedNodes.length === 1) {
755
761
  // Deadends
756
762
  let previousNode = node.connectedNodes[0]
757
763
  let nextNode = {}
@@ -976,7 +982,7 @@ ocargo.Drawing = function (startingPosition) {
976
982
  }
977
983
 
978
984
  this.wait = function (duration, callback) {
979
- character.wait(duration, callback)
985
+ character.wait(duration, callback);
980
986
  }
981
987
 
982
988
  this.deliver = function (destinationId, duration) {
@@ -1015,10 +1021,10 @@ ocargo.Drawing.translate = function (coordinate) {
1015
1021
 
1016
1022
  // A Function used to stop the iframe video
1017
1023
  function stopVideo() {
1018
- // https://gist.github.com/cferdinandi/9044694
1019
- const video = document.getElementsByClassName("video");
1020
- const iframeSrc = video[0].src;
1021
- video[0].src = iframeSrc;
1024
+ // // https://gist.github.com/cferdinandi/9044694
1025
+ const video = document.getElementsByTagName("video");
1026
+ const videoSrc = video[0].src;
1027
+ video[0].src = videoSrc;
1022
1028
  }
1023
1029
 
1024
1030
  /*
@@ -1036,28 +1042,31 @@ ocargo.Drawing.startPopup = function (
1036
1042
  title,
1037
1043
  subtitle,
1038
1044
  message,
1039
- mascot,
1045
+ showMascot,
1040
1046
  buttons
1041
1047
  ) {
1042
1048
  $('#myModal-title').html(title)
1043
1049
  $('#myModal-lead').html(subtitle)
1044
1050
  $('#myModal-mainText').html(message)
1045
1051
 
1046
- $('#modal-mascot').hide()
1047
- $('#modal-mascot--brain').hide()
1052
+ const mascot = $('#modal-mascot')
1053
+ const brain = $('#modal-mascot--brain')
1054
+
1055
+ mascot.hide()
1056
+ brain.hide()
1048
1057
 
1049
- if (mascot) {
1058
+ if (showMascot) {
1050
1059
  if (EPISODE === 9) {
1051
- $('#modal-mascot--brain').show()
1060
+ brain.show()
1052
1061
  }
1053
1062
  else {
1054
- $('#modal-mascot').show()
1063
+ mascot.show()
1055
1064
  }
1056
1065
  }
1057
1066
 
1058
- const youtubeVideo = $("iframe")
1059
- if (youtubeVideo[0]) {
1060
- $("#modal-mascot").hide()
1067
+ const video = $("video")
1068
+ if (video) {
1069
+ mascot.hide()
1061
1070
  }
1062
1071
 
1063
1072
  // create a wrapper for the buttons that will be appended
@@ -1081,7 +1090,7 @@ ocargo.Drawing.startPopup = function (
1081
1090
 
1082
1091
  const regexID = /id=\"*\w+_\w+\"/
1083
1092
 
1084
- // Close the video on pressing the top right close button
1093
+ // Close the video on pressing the top right close button
1085
1094
  $("#close-modal").click(function () {
1086
1095
  stopVideo();
1087
1096
  });
@@ -1094,11 +1103,13 @@ ocargo.Drawing.startPopup = function (
1094
1103
  let classToBeAdded = currentID === "play_button" ? "navigation_button_portal long_button rapid-router-welcome" : "navigation_button_portal_secondary long_button rapid-router-welcome button--icon"
1095
1104
 
1096
1105
  currentButton.removeClass().addClass(classToBeAdded)
1097
- if (currentID != "play_button") {
1106
+ if (currentID !== "play_button") {
1098
1107
  // adding links to buttons
1099
1108
  currentButton.append(icons[i])
1100
1109
  let currentLink = links[i] === "" ? "" : `window.location.replace('${links[i]}')`
1101
- currentButton.attr("onclick", currentLink)
1110
+ if (!(currentID === "next_button" && NEXT_LEVEL_URL === "/pythonden/")) {
1111
+ currentButton.attr("onclick", currentLink);
1112
+ }
1102
1113
  }
1103
1114
 
1104
1115
  // Close the video on the play button
@@ -1125,6 +1136,14 @@ ocargo.Drawing.startPopup = function (
1125
1136
  editButton.removeClass().addClass("navigation_button_portal long_button rapid-router-welcome")
1126
1137
  buttonDiv.append(editButton)
1127
1138
 
1139
+ let yesButton = $("#yes_button")
1140
+ yesButton.removeClass().addClass("navigation_button_portal long_button rapid-router-welcome")
1141
+ buttonDiv.append(yesButton)
1142
+
1143
+ let noButton = $("#no_button")
1144
+ noButton.removeClass().addClass("navigation_button_portal long_button rapid-router-welcome")
1145
+ buttonDiv.append(noButton)
1146
+
1128
1147
  let nextLevelButton = $("#next_level_button")
1129
1148
  nextLevelButton.removeClass().addClass("navigation_button_portal_secondary long_button rapid-router-welcome button--icon")
1130
1149
  nextLevelButton.append(icons[2])
@@ -1135,6 +1154,10 @@ ocargo.Drawing.startPopup = function (
1135
1154
  playButton.append(icons[2])
1136
1155
  buttonDiv.append(playButton)
1137
1156
 
1157
+ let hintPopupButton = $("#hintPopupBtn")
1158
+ hintPopupButton.removeClass().addClass("navigation_button_portal long_button")
1159
+ buttonDiv.append(hintPopupButton)
1160
+
1138
1161
  $("#modal-buttons").html(buttonDiv)
1139
1162
  } else {
1140
1163
  $('#modal-buttons').html(
@@ -1147,11 +1170,19 @@ ocargo.Drawing.startPopup = function (
1147
1170
  $("#modal-buttons").html(buttonDiv)
1148
1171
  }
1149
1172
  // Show popup
1150
- $("#myModal").show()
1151
- $("#ocargo-modal").show()
1152
- window.location.hash = 'myModal'
1173
+ $("#myModal").addClass("show");
1174
+ $("#ocargo-modal").addClass("show");
1175
+ }
1176
+
1177
+ var hideModal = function() {
1178
+ $("#myModal").removeClass("show");
1179
+ $("#ocargo-modal").removeClass("show");
1153
1180
  }
1154
1181
 
1182
+ $("#close-modal").on('click', function() {
1183
+ hideModal();
1184
+ })
1185
+
1155
1186
  // This is the function that starts the pop-up with a yes and a no button
1156
1187
  ocargo.Drawing.startYesNoPopup = function (
1157
1188
  title,
@@ -1159,13 +1190,15 @@ ocargo.Drawing.startYesNoPopup = function (
1159
1190
  message,
1160
1191
  yesFunction,
1161
1192
  noFunction,
1162
- mascot
1193
+ showMascot
1163
1194
  ) {
1164
- let buttonHtml =
1165
- '<button id="modal-yesBtn" class="navigation_button long_button">Yes</button> <button id="modal-noBtn" class="navigation_button long_button">No</button>'
1166
- ocargo.Drawing.startPopup(title, subtitle, message, mascot, buttonHtml)
1167
- $('#modal-yesBtn').click(yesFunction)
1168
- $('#modal-noBtn').click(noFunction)
1195
+ let buttons = '';
1196
+ buttons += ocargo.button.dismissButtonHtml("yes_button", "Yes");
1197
+ buttons += ocargo.button.dismissButtonHtml("no_button", "No");
1198
+
1199
+ ocargo.Drawing.startPopup(title, subtitle, message, showMascot, buttons)
1200
+ $('#yes_button').click(yesFunction)
1201
+ $('#no_button').click(noFunction)
1169
1202
  }
1170
1203
 
1171
1204
  // This is the function that starts the pop-up when there is no internet connection while playing the game
@@ -1214,11 +1247,14 @@ ocargo.Drawing.renderCoins = function (coins) {
1214
1247
  }
1215
1248
 
1216
1249
  ocargo.Drawing.cowUrl = function (type) {
1250
+ ocargo.Drawing.animalType = type;
1217
1251
  switch (type) {
1218
1252
  case ocargo.Cow.WHITE:
1219
1253
  return ocargo.Drawing.whiteCowUrl
1220
1254
  case ocargo.Cow.BROWN:
1221
1255
  return ocargo.Drawing.brownCowUrl
1256
+ case ocargo.Cow.PIGEON:
1257
+ return ocargo.Drawing.pigeonUrl
1222
1258
  default:
1223
1259
  return ocargo.Drawing.whiteCowUrl
1224
1260
  }
@@ -1262,6 +1298,9 @@ ocargo.Drawing.TOP_VIEW = 'top_view'
1262
1298
 
1263
1299
  ocargo.Drawing.whiteCowUrl = 'Clarice.svg'
1264
1300
  ocargo.Drawing.brownCowUrl = 'Clarice_Jersey.svg'
1301
+ ocargo.Drawing.pigeonUrl = 'pigeon.svg'
1265
1302
 
1266
1303
  ocargo.Drawing.imageDir = '/static/game/image/'
1267
1304
  ocargo.Drawing.raphaelImageDir = '/static/game/raphael_image/'
1305
+
1306
+ ocargo.Drawing.animalType = 'WHITE'
@@ -0,0 +1,23 @@
1
+ $(document).ready(function () {
2
+ let shadowRoot = $("editor-wc")[0].shadowRoot;
3
+
4
+ // Set editor height and margin
5
+ $(shadowRoot).find("#root").css("height", "100%");
6
+ $(shadowRoot).find(".proj-container").css("margin", "0 10px 0 0");
7
+
8
+ // Fix project bar height
9
+ $(shadowRoot).find(".project-bar").css("block-size", "auto");
10
+
11
+ // Focus on text output tab
12
+ $(shadowRoot).find(".react-tabs__tab-text").click();
13
+
14
+ // Remove visual output and split view tabs
15
+ $(shadowRoot).find("#react-tabs-4").hide();
16
+ $(shadowRoot).find(".output-view-toggle").hide();
17
+
18
+ // Make editor font size not small
19
+ $(shadowRoot).find(".editor").removeClass("editor--small");
20
+
21
+ // Ensure window doesn't scroll to bottom of page
22
+ window.scrollTo(0, 0);
23
+ });