1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
26 #define DEBUG_INIT_PLAYER 1
27 #define DEBUG_PLAYER_ACTIONS 0
29 /* EXPERIMENTAL STUFF */
30 #define USE_NEW_AMOEBA_CODE FALSE
32 /* EXPERIMENTAL STUFF */
33 #define USE_QUICKSAND_BD_ROCK_BUGFIX 0
34 #define USE_QUICKSAND_IMPACT_BUGFIX 0
35 #define USE_DELAYED_GFX_REDRAW 0
36 #define USE_NEW_PLAYER_ASSIGNMENTS 1
38 #if USE_DELAYED_GFX_REDRAW
39 #define TEST_DrawLevelField(x, y) \
40 GfxRedraw[x][y] |= GFX_REDRAW_TILE
41 #define TEST_DrawLevelFieldCrumbled(x, y) \
42 GfxRedraw[x][y] |= GFX_REDRAW_TILE_CRUMBLED
43 #define TEST_DrawLevelFieldCrumbledNeighbours(x, y) \
44 GfxRedraw[x][y] |= GFX_REDRAW_TILE_CRUMBLED_NEIGHBOURS
45 #define TEST_DrawTwinkleOnField(x, y) \
46 GfxRedraw[x][y] |= GFX_REDRAW_TILE_TWINKLED
48 #define TEST_DrawLevelField(x, y) \
50 #define TEST_DrawLevelFieldCrumbled(x, y) \
51 DrawLevelFieldCrumbled(x, y)
52 #define TEST_DrawLevelFieldCrumbledNeighbours(x, y) \
53 DrawLevelFieldCrumbledNeighbours(x, y)
54 #define TEST_DrawTwinkleOnField(x, y) \
55 DrawTwinkleOnField(x, y)
64 /* for MovePlayer() */
65 #define MP_NO_ACTION 0
68 #define MP_DONT_RUN_INTO (MP_MOVING | MP_ACTION)
70 /* for ScrollPlayer() */
72 #define SCROLL_GO_ON 1
74 /* for Bang()/Explode() */
75 #define EX_PHASE_START 0
76 #define EX_TYPE_NONE 0
77 #define EX_TYPE_NORMAL (1 << 0)
78 #define EX_TYPE_CENTER (1 << 1)
79 #define EX_TYPE_BORDER (1 << 2)
80 #define EX_TYPE_CROSS (1 << 3)
81 #define EX_TYPE_DYNA (1 << 4)
82 #define EX_TYPE_SINGLE_TILE (EX_TYPE_CENTER | EX_TYPE_BORDER)
84 #define PANEL_OFF() (local_player->LevelSolved_PanelOff)
85 #define PANEL_DEACTIVATED(p) ((p)->x < 0 || (p)->y < 0 || PANEL_OFF())
86 #define PANEL_XPOS(p) (DX + ALIGNED_TEXT_XPOS(p))
87 #define PANEL_YPOS(p) (DY + ALIGNED_TEXT_YPOS(p))
89 /* game panel display and control definitions */
90 #define GAME_PANEL_LEVEL_NUMBER 0
91 #define GAME_PANEL_GEMS 1
92 #define GAME_PANEL_INVENTORY_COUNT 2
93 #define GAME_PANEL_INVENTORY_FIRST_1 3
94 #define GAME_PANEL_INVENTORY_FIRST_2 4
95 #define GAME_PANEL_INVENTORY_FIRST_3 5
96 #define GAME_PANEL_INVENTORY_FIRST_4 6
97 #define GAME_PANEL_INVENTORY_FIRST_5 7
98 #define GAME_PANEL_INVENTORY_FIRST_6 8
99 #define GAME_PANEL_INVENTORY_FIRST_7 9
100 #define GAME_PANEL_INVENTORY_FIRST_8 10
101 #define GAME_PANEL_INVENTORY_LAST_1 11
102 #define GAME_PANEL_INVENTORY_LAST_2 12
103 #define GAME_PANEL_INVENTORY_LAST_3 13
104 #define GAME_PANEL_INVENTORY_LAST_4 14
105 #define GAME_PANEL_INVENTORY_LAST_5 15
106 #define GAME_PANEL_INVENTORY_LAST_6 16
107 #define GAME_PANEL_INVENTORY_LAST_7 17
108 #define GAME_PANEL_INVENTORY_LAST_8 18
109 #define GAME_PANEL_KEY_1 19
110 #define GAME_PANEL_KEY_2 20
111 #define GAME_PANEL_KEY_3 21
112 #define GAME_PANEL_KEY_4 22
113 #define GAME_PANEL_KEY_5 23
114 #define GAME_PANEL_KEY_6 24
115 #define GAME_PANEL_KEY_7 25
116 #define GAME_PANEL_KEY_8 26
117 #define GAME_PANEL_KEY_WHITE 27
118 #define GAME_PANEL_KEY_WHITE_COUNT 28
119 #define GAME_PANEL_SCORE 29
120 #define GAME_PANEL_HIGHSCORE 30
121 #define GAME_PANEL_TIME 31
122 #define GAME_PANEL_TIME_HH 32
123 #define GAME_PANEL_TIME_MM 33
124 #define GAME_PANEL_TIME_SS 34
125 #define GAME_PANEL_FRAME 35
126 #define GAME_PANEL_SHIELD_NORMAL 36
127 #define GAME_PANEL_SHIELD_NORMAL_TIME 37
128 #define GAME_PANEL_SHIELD_DEADLY 38
129 #define GAME_PANEL_SHIELD_DEADLY_TIME 39
130 #define GAME_PANEL_EXIT 40
131 #define GAME_PANEL_EMC_MAGIC_BALL 41
132 #define GAME_PANEL_EMC_MAGIC_BALL_SWITCH 42
133 #define GAME_PANEL_LIGHT_SWITCH 43
134 #define GAME_PANEL_LIGHT_SWITCH_TIME 44
135 #define GAME_PANEL_TIMEGATE_SWITCH 45
136 #define GAME_PANEL_TIMEGATE_SWITCH_TIME 46
137 #define GAME_PANEL_SWITCHGATE_SWITCH 47
138 #define GAME_PANEL_EMC_LENSES 48
139 #define GAME_PANEL_EMC_LENSES_TIME 49
140 #define GAME_PANEL_EMC_MAGNIFIER 50
141 #define GAME_PANEL_EMC_MAGNIFIER_TIME 51
142 #define GAME_PANEL_BALLOON_SWITCH 52
143 #define GAME_PANEL_DYNABOMB_NUMBER 53
144 #define GAME_PANEL_DYNABOMB_SIZE 54
145 #define GAME_PANEL_DYNABOMB_POWER 55
146 #define GAME_PANEL_PENGUINS 56
147 #define GAME_PANEL_SOKOBAN_OBJECTS 57
148 #define GAME_PANEL_SOKOBAN_FIELDS 58
149 #define GAME_PANEL_ROBOT_WHEEL 59
150 #define GAME_PANEL_CONVEYOR_BELT_1 60
151 #define GAME_PANEL_CONVEYOR_BELT_2 61
152 #define GAME_PANEL_CONVEYOR_BELT_3 62
153 #define GAME_PANEL_CONVEYOR_BELT_4 63
154 #define GAME_PANEL_CONVEYOR_BELT_1_SWITCH 64
155 #define GAME_PANEL_CONVEYOR_BELT_2_SWITCH 65
156 #define GAME_PANEL_CONVEYOR_BELT_3_SWITCH 66
157 #define GAME_PANEL_CONVEYOR_BELT_4_SWITCH 67
158 #define GAME_PANEL_MAGIC_WALL 68
159 #define GAME_PANEL_MAGIC_WALL_TIME 69
160 #define GAME_PANEL_GRAVITY_STATE 70
161 #define GAME_PANEL_GRAPHIC_1 71
162 #define GAME_PANEL_GRAPHIC_2 72
163 #define GAME_PANEL_GRAPHIC_3 73
164 #define GAME_PANEL_GRAPHIC_4 74
165 #define GAME_PANEL_GRAPHIC_5 75
166 #define GAME_PANEL_GRAPHIC_6 76
167 #define GAME_PANEL_GRAPHIC_7 77
168 #define GAME_PANEL_GRAPHIC_8 78
169 #define GAME_PANEL_ELEMENT_1 79
170 #define GAME_PANEL_ELEMENT_2 80
171 #define GAME_PANEL_ELEMENT_3 81
172 #define GAME_PANEL_ELEMENT_4 82
173 #define GAME_PANEL_ELEMENT_5 83
174 #define GAME_PANEL_ELEMENT_6 84
175 #define GAME_PANEL_ELEMENT_7 85
176 #define GAME_PANEL_ELEMENT_8 86
177 #define GAME_PANEL_ELEMENT_COUNT_1 87
178 #define GAME_PANEL_ELEMENT_COUNT_2 88
179 #define GAME_PANEL_ELEMENT_COUNT_3 89
180 #define GAME_PANEL_ELEMENT_COUNT_4 90
181 #define GAME_PANEL_ELEMENT_COUNT_5 91
182 #define GAME_PANEL_ELEMENT_COUNT_6 92
183 #define GAME_PANEL_ELEMENT_COUNT_7 93
184 #define GAME_PANEL_ELEMENT_COUNT_8 94
185 #define GAME_PANEL_CE_SCORE_1 95
186 #define GAME_PANEL_CE_SCORE_2 96
187 #define GAME_PANEL_CE_SCORE_3 97
188 #define GAME_PANEL_CE_SCORE_4 98
189 #define GAME_PANEL_CE_SCORE_5 99
190 #define GAME_PANEL_CE_SCORE_6 100
191 #define GAME_PANEL_CE_SCORE_7 101
192 #define GAME_PANEL_CE_SCORE_8 102
193 #define GAME_PANEL_CE_SCORE_1_ELEMENT 103
194 #define GAME_PANEL_CE_SCORE_2_ELEMENT 104
195 #define GAME_PANEL_CE_SCORE_3_ELEMENT 105
196 #define GAME_PANEL_CE_SCORE_4_ELEMENT 106
197 #define GAME_PANEL_CE_SCORE_5_ELEMENT 107
198 #define GAME_PANEL_CE_SCORE_6_ELEMENT 108
199 #define GAME_PANEL_CE_SCORE_7_ELEMENT 109
200 #define GAME_PANEL_CE_SCORE_8_ELEMENT 110
201 #define GAME_PANEL_PLAYER_NAME 111
202 #define GAME_PANEL_LEVEL_NAME 112
203 #define GAME_PANEL_LEVEL_AUTHOR 113
205 #define NUM_GAME_PANEL_CONTROLS 114
207 struct GamePanelOrderInfo
213 static struct GamePanelOrderInfo game_panel_order[NUM_GAME_PANEL_CONTROLS];
215 struct GamePanelControlInfo
219 struct TextPosInfo *pos;
222 int value, last_value;
223 int frame, last_frame;
228 static struct GamePanelControlInfo game_panel_controls[] =
231 GAME_PANEL_LEVEL_NUMBER,
232 &game.panel.level_number,
241 GAME_PANEL_INVENTORY_COUNT,
242 &game.panel.inventory_count,
246 GAME_PANEL_INVENTORY_FIRST_1,
247 &game.panel.inventory_first[0],
251 GAME_PANEL_INVENTORY_FIRST_2,
252 &game.panel.inventory_first[1],
256 GAME_PANEL_INVENTORY_FIRST_3,
257 &game.panel.inventory_first[2],
261 GAME_PANEL_INVENTORY_FIRST_4,
262 &game.panel.inventory_first[3],
266 GAME_PANEL_INVENTORY_FIRST_5,
267 &game.panel.inventory_first[4],
271 GAME_PANEL_INVENTORY_FIRST_6,
272 &game.panel.inventory_first[5],
276 GAME_PANEL_INVENTORY_FIRST_7,
277 &game.panel.inventory_first[6],
281 GAME_PANEL_INVENTORY_FIRST_8,
282 &game.panel.inventory_first[7],
286 GAME_PANEL_INVENTORY_LAST_1,
287 &game.panel.inventory_last[0],
291 GAME_PANEL_INVENTORY_LAST_2,
292 &game.panel.inventory_last[1],
296 GAME_PANEL_INVENTORY_LAST_3,
297 &game.panel.inventory_last[2],
301 GAME_PANEL_INVENTORY_LAST_4,
302 &game.panel.inventory_last[3],
306 GAME_PANEL_INVENTORY_LAST_5,
307 &game.panel.inventory_last[4],
311 GAME_PANEL_INVENTORY_LAST_6,
312 &game.panel.inventory_last[5],
316 GAME_PANEL_INVENTORY_LAST_7,
317 &game.panel.inventory_last[6],
321 GAME_PANEL_INVENTORY_LAST_8,
322 &game.panel.inventory_last[7],
366 GAME_PANEL_KEY_WHITE,
367 &game.panel.key_white,
371 GAME_PANEL_KEY_WHITE_COUNT,
372 &game.panel.key_white_count,
381 GAME_PANEL_HIGHSCORE,
382 &game.panel.highscore,
411 GAME_PANEL_SHIELD_NORMAL,
412 &game.panel.shield_normal,
416 GAME_PANEL_SHIELD_NORMAL_TIME,
417 &game.panel.shield_normal_time,
421 GAME_PANEL_SHIELD_DEADLY,
422 &game.panel.shield_deadly,
426 GAME_PANEL_SHIELD_DEADLY_TIME,
427 &game.panel.shield_deadly_time,
436 GAME_PANEL_EMC_MAGIC_BALL,
437 &game.panel.emc_magic_ball,
441 GAME_PANEL_EMC_MAGIC_BALL_SWITCH,
442 &game.panel.emc_magic_ball_switch,
446 GAME_PANEL_LIGHT_SWITCH,
447 &game.panel.light_switch,
451 GAME_PANEL_LIGHT_SWITCH_TIME,
452 &game.panel.light_switch_time,
456 GAME_PANEL_TIMEGATE_SWITCH,
457 &game.panel.timegate_switch,
461 GAME_PANEL_TIMEGATE_SWITCH_TIME,
462 &game.panel.timegate_switch_time,
466 GAME_PANEL_SWITCHGATE_SWITCH,
467 &game.panel.switchgate_switch,
471 GAME_PANEL_EMC_LENSES,
472 &game.panel.emc_lenses,
476 GAME_PANEL_EMC_LENSES_TIME,
477 &game.panel.emc_lenses_time,
481 GAME_PANEL_EMC_MAGNIFIER,
482 &game.panel.emc_magnifier,
486 GAME_PANEL_EMC_MAGNIFIER_TIME,
487 &game.panel.emc_magnifier_time,
491 GAME_PANEL_BALLOON_SWITCH,
492 &game.panel.balloon_switch,
496 GAME_PANEL_DYNABOMB_NUMBER,
497 &game.panel.dynabomb_number,
501 GAME_PANEL_DYNABOMB_SIZE,
502 &game.panel.dynabomb_size,
506 GAME_PANEL_DYNABOMB_POWER,
507 &game.panel.dynabomb_power,
512 &game.panel.penguins,
516 GAME_PANEL_SOKOBAN_OBJECTS,
517 &game.panel.sokoban_objects,
521 GAME_PANEL_SOKOBAN_FIELDS,
522 &game.panel.sokoban_fields,
526 GAME_PANEL_ROBOT_WHEEL,
527 &game.panel.robot_wheel,
531 GAME_PANEL_CONVEYOR_BELT_1,
532 &game.panel.conveyor_belt[0],
536 GAME_PANEL_CONVEYOR_BELT_2,
537 &game.panel.conveyor_belt[1],
541 GAME_PANEL_CONVEYOR_BELT_3,
542 &game.panel.conveyor_belt[2],
546 GAME_PANEL_CONVEYOR_BELT_4,
547 &game.panel.conveyor_belt[3],
551 GAME_PANEL_CONVEYOR_BELT_1_SWITCH,
552 &game.panel.conveyor_belt_switch[0],
556 GAME_PANEL_CONVEYOR_BELT_2_SWITCH,
557 &game.panel.conveyor_belt_switch[1],
561 GAME_PANEL_CONVEYOR_BELT_3_SWITCH,
562 &game.panel.conveyor_belt_switch[2],
566 GAME_PANEL_CONVEYOR_BELT_4_SWITCH,
567 &game.panel.conveyor_belt_switch[3],
571 GAME_PANEL_MAGIC_WALL,
572 &game.panel.magic_wall,
576 GAME_PANEL_MAGIC_WALL_TIME,
577 &game.panel.magic_wall_time,
581 GAME_PANEL_GRAVITY_STATE,
582 &game.panel.gravity_state,
586 GAME_PANEL_GRAPHIC_1,
587 &game.panel.graphic[0],
591 GAME_PANEL_GRAPHIC_2,
592 &game.panel.graphic[1],
596 GAME_PANEL_GRAPHIC_3,
597 &game.panel.graphic[2],
601 GAME_PANEL_GRAPHIC_4,
602 &game.panel.graphic[3],
606 GAME_PANEL_GRAPHIC_5,
607 &game.panel.graphic[4],
611 GAME_PANEL_GRAPHIC_6,
612 &game.panel.graphic[5],
616 GAME_PANEL_GRAPHIC_7,
617 &game.panel.graphic[6],
621 GAME_PANEL_GRAPHIC_8,
622 &game.panel.graphic[7],
626 GAME_PANEL_ELEMENT_1,
627 &game.panel.element[0],
631 GAME_PANEL_ELEMENT_2,
632 &game.panel.element[1],
636 GAME_PANEL_ELEMENT_3,
637 &game.panel.element[2],
641 GAME_PANEL_ELEMENT_4,
642 &game.panel.element[3],
646 GAME_PANEL_ELEMENT_5,
647 &game.panel.element[4],
651 GAME_PANEL_ELEMENT_6,
652 &game.panel.element[5],
656 GAME_PANEL_ELEMENT_7,
657 &game.panel.element[6],
661 GAME_PANEL_ELEMENT_8,
662 &game.panel.element[7],
666 GAME_PANEL_ELEMENT_COUNT_1,
667 &game.panel.element_count[0],
671 GAME_PANEL_ELEMENT_COUNT_2,
672 &game.panel.element_count[1],
676 GAME_PANEL_ELEMENT_COUNT_3,
677 &game.panel.element_count[2],
681 GAME_PANEL_ELEMENT_COUNT_4,
682 &game.panel.element_count[3],
686 GAME_PANEL_ELEMENT_COUNT_5,
687 &game.panel.element_count[4],
691 GAME_PANEL_ELEMENT_COUNT_6,
692 &game.panel.element_count[5],
696 GAME_PANEL_ELEMENT_COUNT_7,
697 &game.panel.element_count[6],
701 GAME_PANEL_ELEMENT_COUNT_8,
702 &game.panel.element_count[7],
706 GAME_PANEL_CE_SCORE_1,
707 &game.panel.ce_score[0],
711 GAME_PANEL_CE_SCORE_2,
712 &game.panel.ce_score[1],
716 GAME_PANEL_CE_SCORE_3,
717 &game.panel.ce_score[2],
721 GAME_PANEL_CE_SCORE_4,
722 &game.panel.ce_score[3],
726 GAME_PANEL_CE_SCORE_5,
727 &game.panel.ce_score[4],
731 GAME_PANEL_CE_SCORE_6,
732 &game.panel.ce_score[5],
736 GAME_PANEL_CE_SCORE_7,
737 &game.panel.ce_score[6],
741 GAME_PANEL_CE_SCORE_8,
742 &game.panel.ce_score[7],
746 GAME_PANEL_CE_SCORE_1_ELEMENT,
747 &game.panel.ce_score_element[0],
751 GAME_PANEL_CE_SCORE_2_ELEMENT,
752 &game.panel.ce_score_element[1],
756 GAME_PANEL_CE_SCORE_3_ELEMENT,
757 &game.panel.ce_score_element[2],
761 GAME_PANEL_CE_SCORE_4_ELEMENT,
762 &game.panel.ce_score_element[3],
766 GAME_PANEL_CE_SCORE_5_ELEMENT,
767 &game.panel.ce_score_element[4],
771 GAME_PANEL_CE_SCORE_6_ELEMENT,
772 &game.panel.ce_score_element[5],
776 GAME_PANEL_CE_SCORE_7_ELEMENT,
777 &game.panel.ce_score_element[6],
781 GAME_PANEL_CE_SCORE_8_ELEMENT,
782 &game.panel.ce_score_element[7],
786 GAME_PANEL_PLAYER_NAME,
787 &game.panel.player_name,
791 GAME_PANEL_LEVEL_NAME,
792 &game.panel.level_name,
796 GAME_PANEL_LEVEL_AUTHOR,
797 &game.panel.level_author,
808 /* values for delayed check of falling and moving elements and for collision */
809 #define CHECK_DELAY_MOVING 3
810 #define CHECK_DELAY_FALLING CHECK_DELAY_MOVING
811 #define CHECK_DELAY_COLLISION 2
812 #define CHECK_DELAY_IMPACT CHECK_DELAY_COLLISION
814 /* values for initial player move delay (initial delay counter value) */
815 #define INITIAL_MOVE_DELAY_OFF -1
816 #define INITIAL_MOVE_DELAY_ON 0
818 /* values for player movement speed (which is in fact a delay value) */
819 #define MOVE_DELAY_MIN_SPEED 32
820 #define MOVE_DELAY_NORMAL_SPEED 8
821 #define MOVE_DELAY_HIGH_SPEED 4
822 #define MOVE_DELAY_MAX_SPEED 1
824 #define DOUBLE_MOVE_DELAY(x) (x = (x < MOVE_DELAY_MIN_SPEED ? x * 2 : x))
825 #define HALVE_MOVE_DELAY(x) (x = (x > MOVE_DELAY_MAX_SPEED ? x / 2 : x))
827 #define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY( (p)->move_delay_value))
828 #define HALVE_PLAYER_SPEED(p) (DOUBLE_MOVE_DELAY((p)->move_delay_value))
830 /* values for scroll positions */
831 #define SCROLL_POSITION_X(x) ((x) < SBX_Left + MIDPOSX ? SBX_Left : \
832 (x) > SBX_Right + MIDPOSX ? SBX_Right :\
834 #define SCROLL_POSITION_Y(y) ((y) < SBY_Upper + MIDPOSY ? SBY_Upper :\
835 (y) > SBY_Lower + MIDPOSY ? SBY_Lower :\
838 /* values for other actions */
839 #define MOVE_STEPSIZE_NORMAL (TILEX / MOVE_DELAY_NORMAL_SPEED)
840 #define MOVE_STEPSIZE_MIN (1)
841 #define MOVE_STEPSIZE_MAX (TILEX)
843 #define GET_DX_FROM_DIR(d) ((d) == MV_LEFT ? -1 : (d) == MV_RIGHT ? 1 : 0)
844 #define GET_DY_FROM_DIR(d) ((d) == MV_UP ? -1 : (d) == MV_DOWN ? 1 : 0)
846 #define INIT_GFX_RANDOM() (GetSimpleRandom(1000000))
848 #define GET_NEW_PUSH_DELAY(e) ( (element_info[e].push_delay_fixed) + \
849 RND(element_info[e].push_delay_random))
850 #define GET_NEW_DROP_DELAY(e) ( (element_info[e].drop_delay_fixed) + \
851 RND(element_info[e].drop_delay_random))
852 #define GET_NEW_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \
853 RND(element_info[e].move_delay_random))
854 #define GET_MAX_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \
855 (element_info[e].move_delay_random))
856 #define GET_NEW_CE_VALUE(e) ( (element_info[e].ce_value_fixed_initial) +\
857 RND(element_info[e].ce_value_random_initial))
858 #define GET_CE_SCORE(e) ( (element_info[e].collect_score))
859 #define GET_CHANGE_DELAY(c) ( ((c)->delay_fixed * (c)->delay_frames) + \
860 RND((c)->delay_random * (c)->delay_frames))
861 #define GET_CE_DELAY_VALUE(c) ( ((c)->delay_fixed) + \
862 RND((c)->delay_random))
865 #define GET_VALID_RUNTIME_ELEMENT(e) \
866 ((e) >= NUM_RUNTIME_ELEMENTS ? EL_UNKNOWN : (e))
868 #define RESOLVED_REFERENCE_ELEMENT(be, e) \
869 ((be) + (e) - EL_SELF < EL_CUSTOM_START ? EL_CUSTOM_START : \
870 (be) + (e) - EL_SELF > EL_CUSTOM_END ? EL_CUSTOM_END : \
871 (be) + (e) - EL_SELF)
873 #define GET_PLAYER_FROM_BITS(p) \
874 (EL_PLAYER_1 + ((p) != PLAYER_BITS_ANY ? log_2(p) : 0))
876 #define GET_TARGET_ELEMENT(be, e, ch, cv, cs) \
877 ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \
878 (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \
879 (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value : \
880 (e) == EL_TRIGGER_CE_SCORE ? (ch)->actual_trigger_ce_score : \
881 (e) == EL_CURRENT_CE_VALUE ? (cv) : \
882 (e) == EL_CURRENT_CE_SCORE ? (cs) : \
883 (e) >= EL_PREV_CE_8 && (e) <= EL_NEXT_CE_8 ? \
884 RESOLVED_REFERENCE_ELEMENT(be, e) : \
887 #define CAN_GROW_INTO(e) \
888 ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
890 #define ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, condition) \
891 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
894 #define ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, condition) \
895 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
896 (CAN_MOVE_INTO_ACID(e) && \
897 Feld[x][y] == EL_ACID) || \
900 #define ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, condition) \
901 (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \
902 (CAN_MOVE_INTO_ACID(e) && \
903 Feld[x][y] == EL_ACID) || \
906 #define ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, condition) \
907 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
909 (CAN_MOVE_INTO_ACID(e) && \
910 Feld[x][y] == EL_ACID) || \
911 (DONT_COLLIDE_WITH(e) && \
913 !PLAYER_ENEMY_PROTECTED(x, y))))
915 #define ELEMENT_CAN_ENTER_FIELD(e, x, y) \
916 ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, 0)
918 #define SATELLITE_CAN_ENTER_FIELD(x, y) \
919 ELEMENT_CAN_ENTER_FIELD_BASE_2(EL_SATELLITE, x, y, 0)
921 #define ANDROID_CAN_ENTER_FIELD(e, x, y) \
922 ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, Feld[x][y] == EL_EMC_PLANT)
924 #define ANDROID_CAN_CLONE_FIELD(x, y) \
925 (IN_LEV_FIELD(x, y) && (CAN_BE_CLONED_BY_ANDROID(Feld[x][y]) || \
926 CAN_BE_CLONED_BY_ANDROID(EL_TRIGGER_ELEMENT)))
928 #define ENEMY_CAN_ENTER_FIELD(e, x, y) \
929 ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
931 #define YAMYAM_CAN_ENTER_FIELD(e, x, y) \
932 ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Feld[x][y] == EL_DIAMOND)
934 #define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y) \
935 ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Feld[x][y]))
937 #define PACMAN_CAN_ENTER_FIELD(e, x, y) \
938 ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Feld[x][y]))
940 #define PIG_CAN_ENTER_FIELD(e, x, y) \
941 ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, IS_FOOD_PIG(Feld[x][y]))
943 #define PENGUIN_CAN_ENTER_FIELD(e, x, y) \
944 ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (Feld[x][y] == EL_EXIT_OPEN || \
945 Feld[x][y] == EL_EM_EXIT_OPEN || \
946 Feld[x][y] == EL_STEEL_EXIT_OPEN || \
947 Feld[x][y] == EL_EM_STEEL_EXIT_OPEN || \
948 IS_FOOD_PENGUIN(Feld[x][y])))
949 #define DRAGON_CAN_ENTER_FIELD(e, x, y) \
950 ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
952 #define MOLE_CAN_ENTER_FIELD(e, x, y, condition) \
953 ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (condition))
955 #define SPRING_CAN_ENTER_FIELD(e, x, y) \
956 ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
958 #define SPRING_CAN_BUMP_FROM_FIELD(x, y) \
959 (IN_LEV_FIELD(x, y) && (Feld[x][y] == EL_EMC_SPRING_BUMPER || \
960 Feld[x][y] == EL_EMC_SPRING_BUMPER_ACTIVE))
962 #define MOVE_ENTER_EL(e) (element_info[e].move_enter_element)
964 #define CE_ENTER_FIELD_COND(e, x, y) \
965 (!IS_PLAYER(x, y) && \
966 IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e)))
968 #define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y) \
969 ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, CE_ENTER_FIELD_COND(e, x, y))
971 #define IN_LEV_FIELD_AND_IS_FREE(x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
972 #define IN_LEV_FIELD_AND_NOT_FREE(x, y) (IN_LEV_FIELD(x, y) && !IS_FREE(x, y))
974 #define ACCESS_FROM(e, d) (element_info[e].access_direction &(d))
975 #define IS_WALKABLE_FROM(e, d) (IS_WALKABLE(e) && ACCESS_FROM(e, d))
976 #define IS_PASSABLE_FROM(e, d) (IS_PASSABLE(e) && ACCESS_FROM(e, d))
977 #define IS_ACCESSIBLE_FROM(e, d) (IS_ACCESSIBLE(e) && ACCESS_FROM(e, d))
979 /* game button identifiers */
980 #define GAME_CTRL_ID_STOP 0
981 #define GAME_CTRL_ID_PAUSE 1
982 #define GAME_CTRL_ID_PLAY 2
983 #define GAME_CTRL_ID_UNDO 3
984 #define GAME_CTRL_ID_REDO 4
985 #define GAME_CTRL_ID_SAVE 5
986 #define GAME_CTRL_ID_PAUSE2 6
987 #define GAME_CTRL_ID_LOAD 7
988 #define SOUND_CTRL_ID_MUSIC 8
989 #define SOUND_CTRL_ID_LOOPS 9
990 #define SOUND_CTRL_ID_SIMPLE 10
992 #define NUM_GAME_BUTTONS 11
995 /* forward declaration for internal use */
997 static void CreateField(int, int, int);
999 static void ResetGfxAnimation(int, int);
1001 static void SetPlayerWaiting(struct PlayerInfo *, boolean);
1002 static void AdvanceFrameAndPlayerCounters(int);
1004 static boolean MovePlayerOneStep(struct PlayerInfo *, int, int, int, int);
1005 static boolean MovePlayer(struct PlayerInfo *, int, int);
1006 static void ScrollPlayer(struct PlayerInfo *, int);
1007 static void ScrollScreen(struct PlayerInfo *, int);
1009 static int DigField(struct PlayerInfo *, int, int, int, int, int, int, int);
1010 static boolean DigFieldByCE(int, int, int);
1011 static boolean SnapField(struct PlayerInfo *, int, int);
1012 static boolean DropElement(struct PlayerInfo *);
1014 static void InitBeltMovement(void);
1015 static void CloseAllOpenTimegates(void);
1016 static void CheckGravityMovement(struct PlayerInfo *);
1017 static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *);
1018 static void KillPlayerUnlessEnemyProtected(int, int);
1019 static void KillPlayerUnlessExplosionProtected(int, int);
1021 static void TestIfPlayerTouchesCustomElement(int, int);
1022 static void TestIfElementTouchesCustomElement(int, int);
1023 static void TestIfElementHitsCustomElement(int, int, int);
1025 static void HandleElementChange(int, int, int);
1026 static void ExecuteCustomElementAction(int, int, int, int);
1027 static boolean ChangeElement(int, int, int, int);
1029 static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
1030 #define CheckTriggeredElementChange(x, y, e, ev) \
1031 CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY,CH_SIDE_ANY, -1)
1032 #define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s) \
1033 CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1)
1034 #define CheckTriggeredElementChangeBySide(x, y, e, ev, s) \
1035 CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, s, -1)
1036 #define CheckTriggeredElementChangeByPage(x, y, e, ev, p) \
1037 CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY, CH_SIDE_ANY, p)
1039 static boolean CheckElementChangeExt(int, int, int, int, int, int, int);
1040 #define CheckElementChange(x, y, e, te, ev) \
1041 CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY)
1042 #define CheckElementChangeByPlayer(x, y, e, ev, p, s) \
1043 CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s)
1044 #define CheckElementChangeBySide(x, y, e, te, ev, s) \
1045 CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s)
1047 static void PlayLevelSound(int, int, int);
1048 static void PlayLevelSoundNearest(int, int, int);
1049 static void PlayLevelSoundAction(int, int, int);
1050 static void PlayLevelSoundElementAction(int, int, int, int);
1051 static void PlayLevelSoundElementActionIfLoop(int, int, int, int);
1052 static void PlayLevelSoundActionIfLoop(int, int, int);
1053 static void StopLevelSoundActionIfLoop(int, int, int);
1054 static void PlayLevelMusic();
1056 static void HandleGameButtons(struct GadgetInfo *);
1058 int AmoebeNachbarNr(int, int);
1059 void AmoebeUmwandeln(int, int);
1060 void ContinueMoving(int, int);
1061 void Bang(int, int);
1062 void InitMovDir(int, int);
1063 void InitAmoebaNr(int, int);
1064 int NewHiScore(void);
1066 void TestIfGoodThingHitsBadThing(int, int, int);
1067 void TestIfBadThingHitsGoodThing(int, int, int);
1068 void TestIfPlayerTouchesBadThing(int, int);
1069 void TestIfPlayerRunsIntoBadThing(int, int, int);
1070 void TestIfBadThingTouchesPlayer(int, int);
1071 void TestIfBadThingRunsIntoPlayer(int, int, int);
1072 void TestIfFriendTouchesBadThing(int, int);
1073 void TestIfBadThingTouchesFriend(int, int);
1074 void TestIfBadThingTouchesOtherBadThing(int, int);
1075 void TestIfGoodThingGetsHitByBadThing(int, int, int);
1077 void KillPlayer(struct PlayerInfo *);
1078 void BuryPlayer(struct PlayerInfo *);
1079 void RemovePlayer(struct PlayerInfo *);
1081 static int getInvisibleActiveFromInvisibleElement(int);
1082 static int getInvisibleFromInvisibleActiveElement(int);
1084 static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
1086 /* for detection of endless loops, caused by custom element programming */
1087 /* (using maximal playfield width x 10 is just a rough approximation) */
1088 #define MAX_ELEMENT_CHANGE_RECURSION_DEPTH (MAX_PLAYFIELD_WIDTH * 10)
1090 #define RECURSION_LOOP_DETECTION_START(e, rc) \
1092 if (recursion_loop_detected) \
1095 if (recursion_loop_depth > MAX_ELEMENT_CHANGE_RECURSION_DEPTH) \
1097 recursion_loop_detected = TRUE; \
1098 recursion_loop_element = (e); \
1101 recursion_loop_depth++; \
1104 #define RECURSION_LOOP_DETECTION_END() \
1106 recursion_loop_depth--; \
1109 static int recursion_loop_depth;
1110 static boolean recursion_loop_detected;
1111 static boolean recursion_loop_element;
1113 static int map_player_action[MAX_PLAYERS];
1116 /* ------------------------------------------------------------------------- */
1117 /* definition of elements that automatically change to other elements after */
1118 /* a specified time, eventually calling a function when changing */
1119 /* ------------------------------------------------------------------------- */
1121 /* forward declaration for changer functions */
1122 static void InitBuggyBase(int, int);
1123 static void WarnBuggyBase(int, int);
1125 static void InitTrap(int, int);
1126 static void ActivateTrap(int, int);
1127 static void ChangeActiveTrap(int, int);
1129 static void InitRobotWheel(int, int);
1130 static void RunRobotWheel(int, int);
1131 static void StopRobotWheel(int, int);
1133 static void InitTimegateWheel(int, int);
1134 static void RunTimegateWheel(int, int);
1136 static void InitMagicBallDelay(int, int);
1137 static void ActivateMagicBall(int, int);
1139 struct ChangingElementInfo
1144 void (*pre_change_function)(int x, int y);
1145 void (*change_function)(int x, int y);
1146 void (*post_change_function)(int x, int y);
1149 static struct ChangingElementInfo change_delay_list[] =
1184 EL_STEEL_EXIT_OPENING,
1192 EL_STEEL_EXIT_CLOSING,
1193 EL_STEEL_EXIT_CLOSED,
1216 EL_EM_STEEL_EXIT_OPENING,
1217 EL_EM_STEEL_EXIT_OPEN,
1224 EL_EM_STEEL_EXIT_CLOSING,
1248 EL_SWITCHGATE_OPENING,
1256 EL_SWITCHGATE_CLOSING,
1257 EL_SWITCHGATE_CLOSED,
1264 EL_TIMEGATE_OPENING,
1272 EL_TIMEGATE_CLOSING,
1281 EL_ACID_SPLASH_LEFT,
1289 EL_ACID_SPLASH_RIGHT,
1298 EL_SP_BUGGY_BASE_ACTIVATING,
1305 EL_SP_BUGGY_BASE_ACTIVATING,
1306 EL_SP_BUGGY_BASE_ACTIVE,
1313 EL_SP_BUGGY_BASE_ACTIVE,
1337 EL_ROBOT_WHEEL_ACTIVE,
1345 EL_TIMEGATE_SWITCH_ACTIVE,
1353 EL_DC_TIMEGATE_SWITCH_ACTIVE,
1354 EL_DC_TIMEGATE_SWITCH,
1361 EL_EMC_MAGIC_BALL_ACTIVE,
1362 EL_EMC_MAGIC_BALL_ACTIVE,
1369 EL_EMC_SPRING_BUMPER_ACTIVE,
1370 EL_EMC_SPRING_BUMPER,
1377 EL_DIAGONAL_SHRINKING,
1385 EL_DIAGONAL_GROWING,
1406 int push_delay_fixed, push_delay_random;
1410 { EL_SPRING, 0, 0 },
1411 { EL_BALLOON, 0, 0 },
1413 { EL_SOKOBAN_OBJECT, 2, 0 },
1414 { EL_SOKOBAN_FIELD_FULL, 2, 0 },
1415 { EL_SATELLITE, 2, 0 },
1416 { EL_SP_DISK_YELLOW, 2, 0 },
1418 { EL_UNDEFINED, 0, 0 },
1426 move_stepsize_list[] =
1428 { EL_AMOEBA_DROP, 2 },
1429 { EL_AMOEBA_DROPPING, 2 },
1430 { EL_QUICKSAND_FILLING, 1 },
1431 { EL_QUICKSAND_EMPTYING, 1 },
1432 { EL_QUICKSAND_FAST_FILLING, 2 },
1433 { EL_QUICKSAND_FAST_EMPTYING, 2 },
1434 { EL_MAGIC_WALL_FILLING, 2 },
1435 { EL_MAGIC_WALL_EMPTYING, 2 },
1436 { EL_BD_MAGIC_WALL_FILLING, 2 },
1437 { EL_BD_MAGIC_WALL_EMPTYING, 2 },
1438 { EL_DC_MAGIC_WALL_FILLING, 2 },
1439 { EL_DC_MAGIC_WALL_EMPTYING, 2 },
1441 { EL_UNDEFINED, 0 },
1449 collect_count_list[] =
1452 { EL_BD_DIAMOND, 1 },
1453 { EL_EMERALD_YELLOW, 1 },
1454 { EL_EMERALD_RED, 1 },
1455 { EL_EMERALD_PURPLE, 1 },
1457 { EL_SP_INFOTRON, 1 },
1461 { EL_UNDEFINED, 0 },
1469 access_direction_list[] =
1471 { EL_TUBE_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
1472 { EL_TUBE_VERTICAL, MV_UP | MV_DOWN },
1473 { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT },
1474 { EL_TUBE_VERTICAL_LEFT, MV_LEFT | MV_UP | MV_DOWN },
1475 { EL_TUBE_VERTICAL_RIGHT, MV_RIGHT | MV_UP | MV_DOWN },
1476 { EL_TUBE_HORIZONTAL_UP, MV_LEFT | MV_RIGHT | MV_UP },
1477 { EL_TUBE_HORIZONTAL_DOWN, MV_LEFT | MV_RIGHT | MV_DOWN },
1478 { EL_TUBE_LEFT_UP, MV_LEFT | MV_UP },
1479 { EL_TUBE_LEFT_DOWN, MV_LEFT | MV_DOWN },
1480 { EL_TUBE_RIGHT_UP, MV_RIGHT | MV_UP },
1481 { EL_TUBE_RIGHT_DOWN, MV_RIGHT | MV_DOWN },
1483 { EL_SP_PORT_LEFT, MV_RIGHT },
1484 { EL_SP_PORT_RIGHT, MV_LEFT },
1485 { EL_SP_PORT_UP, MV_DOWN },
1486 { EL_SP_PORT_DOWN, MV_UP },
1487 { EL_SP_PORT_HORIZONTAL, MV_LEFT | MV_RIGHT },
1488 { EL_SP_PORT_VERTICAL, MV_UP | MV_DOWN },
1489 { EL_SP_PORT_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
1490 { EL_SP_GRAVITY_PORT_LEFT, MV_RIGHT },
1491 { EL_SP_GRAVITY_PORT_RIGHT, MV_LEFT },
1492 { EL_SP_GRAVITY_PORT_UP, MV_DOWN },
1493 { EL_SP_GRAVITY_PORT_DOWN, MV_UP },
1494 { EL_SP_GRAVITY_ON_PORT_LEFT, MV_RIGHT },
1495 { EL_SP_GRAVITY_ON_PORT_RIGHT, MV_LEFT },
1496 { EL_SP_GRAVITY_ON_PORT_UP, MV_DOWN },
1497 { EL_SP_GRAVITY_ON_PORT_DOWN, MV_UP },
1498 { EL_SP_GRAVITY_OFF_PORT_LEFT, MV_RIGHT },
1499 { EL_SP_GRAVITY_OFF_PORT_RIGHT, MV_LEFT },
1500 { EL_SP_GRAVITY_OFF_PORT_UP, MV_DOWN },
1501 { EL_SP_GRAVITY_OFF_PORT_DOWN, MV_UP },
1503 { EL_UNDEFINED, MV_NONE }
1506 static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS];
1508 #define IS_AUTO_CHANGING(e) (element_info[e].has_change_event[CE_DELAY])
1509 #define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0)
1510 #define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Feld[x][y]) || \
1511 IS_JUST_CHANGING(x, y))
1513 #define CE_PAGE(e, ce) (element_info[e].event_page[ce])
1515 /* static variables for playfield scan mode (scanning forward or backward) */
1516 static int playfield_scan_start_x = 0;
1517 static int playfield_scan_start_y = 0;
1518 static int playfield_scan_delta_x = 1;
1519 static int playfield_scan_delta_y = 1;
1521 #define SCAN_PLAYFIELD(x, y) for ((y) = playfield_scan_start_y; \
1522 (y) >= 0 && (y) <= lev_fieldy - 1; \
1523 (y) += playfield_scan_delta_y) \
1524 for ((x) = playfield_scan_start_x; \
1525 (x) >= 0 && (x) <= lev_fieldx - 1; \
1526 (x) += playfield_scan_delta_x)
1529 void DEBUG_SetMaximumDynamite()
1533 for (i = 0; i < MAX_INVENTORY_SIZE; i++)
1534 if (local_player->inventory_size < MAX_INVENTORY_SIZE)
1535 local_player->inventory_element[local_player->inventory_size++] =
1540 static void InitPlayfieldScanModeVars()
1542 if (game.use_reverse_scan_direction)
1544 playfield_scan_start_x = lev_fieldx - 1;
1545 playfield_scan_start_y = lev_fieldy - 1;
1547 playfield_scan_delta_x = -1;
1548 playfield_scan_delta_y = -1;
1552 playfield_scan_start_x = 0;
1553 playfield_scan_start_y = 0;
1555 playfield_scan_delta_x = 1;
1556 playfield_scan_delta_y = 1;
1560 static void InitPlayfieldScanMode(int mode)
1562 game.use_reverse_scan_direction =
1563 (mode == CA_ARG_SCAN_MODE_REVERSE ? TRUE : FALSE);
1565 InitPlayfieldScanModeVars();
1568 static int get_move_delay_from_stepsize(int move_stepsize)
1571 MIN(MAX(MOVE_STEPSIZE_MIN, move_stepsize), MOVE_STEPSIZE_MAX);
1573 /* make sure that stepsize value is always a power of 2 */
1574 move_stepsize = (1 << log_2(move_stepsize));
1576 return TILEX / move_stepsize;
1579 static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize,
1582 int player_nr = player->index_nr;
1583 int move_delay = get_move_delay_from_stepsize(move_stepsize);
1584 boolean cannot_move = (move_stepsize == STEPSIZE_NOT_MOVING ? TRUE : FALSE);
1586 /* do no immediately change move delay -- the player might just be moving */
1587 player->move_delay_value_next = move_delay;
1589 /* information if player can move must be set separately */
1590 player->cannot_move = cannot_move;
1594 player->move_delay = game.initial_move_delay[player_nr];
1595 player->move_delay_value = game.initial_move_delay_value[player_nr];
1597 player->move_delay_value_next = -1;
1599 player->move_delay_reset_counter = 0;
1603 void GetPlayerConfig()
1605 GameFrameDelay = setup.game_frame_delay;
1607 if (!audio.sound_available)
1608 setup.sound_simple = FALSE;
1610 if (!audio.loops_available)
1611 setup.sound_loops = FALSE;
1613 if (!audio.music_available)
1614 setup.sound_music = FALSE;
1616 if (!video.fullscreen_available)
1617 setup.fullscreen = FALSE;
1619 setup.sound = (setup.sound_simple || setup.sound_loops || setup.sound_music);
1621 SetAudioMode(setup.sound);
1625 int GetElementFromGroupElement(int element)
1627 if (IS_GROUP_ELEMENT(element))
1629 struct ElementGroupInfo *group = element_info[element].group;
1630 int last_anim_random_frame = gfx.anim_random_frame;
1633 if (group->choice_mode == ANIM_RANDOM)
1634 gfx.anim_random_frame = RND(group->num_elements_resolved);
1636 element_pos = getAnimationFrame(group->num_elements_resolved, 1,
1637 group->choice_mode, 0,
1640 if (group->choice_mode == ANIM_RANDOM)
1641 gfx.anim_random_frame = last_anim_random_frame;
1643 group->choice_pos++;
1645 element = group->element_resolved[element_pos];
1651 static void InitPlayerField(int x, int y, int element, boolean init_game)
1653 if (element == EL_SP_MURPHY)
1657 if (stored_player[0].present)
1659 Feld[x][y] = EL_SP_MURPHY_CLONE;
1665 stored_player[0].initial_element = element;
1666 stored_player[0].use_murphy = TRUE;
1668 if (!level.use_artwork_element[0])
1669 stored_player[0].artwork_element = EL_SP_MURPHY;
1672 Feld[x][y] = EL_PLAYER_1;
1678 struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1];
1679 int jx = player->jx, jy = player->jy;
1681 player->present = TRUE;
1683 player->block_last_field = (element == EL_SP_MURPHY ?
1684 level.sp_block_last_field :
1685 level.block_last_field);
1687 /* ---------- initialize player's last field block delay --------------- */
1689 /* always start with reliable default value (no adjustment needed) */
1690 player->block_delay_adjustment = 0;
1692 /* special case 1: in Supaplex, Murphy blocks last field one more frame */
1693 if (player->block_last_field && element == EL_SP_MURPHY)
1694 player->block_delay_adjustment = 1;
1696 /* special case 2: in game engines before 3.1.1, blocking was different */
1697 if (game.use_block_last_field_bug)
1698 player->block_delay_adjustment = (player->block_last_field ? -1 : 1);
1700 if (!options.network || player->connected)
1702 player->active = TRUE;
1704 /* remove potentially duplicate players */
1705 if (StorePlayer[jx][jy] == Feld[x][y])
1706 StorePlayer[jx][jy] = 0;
1708 StorePlayer[x][y] = Feld[x][y];
1710 #if DEBUG_INIT_PLAYER
1713 printf("- player element %d activated", player->element_nr);
1714 printf(" (local player is %d and currently %s)\n",
1715 local_player->element_nr,
1716 local_player->active ? "active" : "not active");
1721 Feld[x][y] = EL_EMPTY;
1723 player->jx = player->last_jx = x;
1724 player->jy = player->last_jy = y;
1729 int player_nr = GET_PLAYER_NR(element);
1730 struct PlayerInfo *player = &stored_player[player_nr];
1732 if (player->active && player->killed)
1733 player->reanimated = TRUE; /* if player was just killed, reanimate him */
1737 static void InitField(int x, int y, boolean init_game)
1739 int element = Feld[x][y];
1748 InitPlayerField(x, y, element, init_game);
1751 case EL_SOKOBAN_FIELD_PLAYER:
1752 element = Feld[x][y] = EL_PLAYER_1;
1753 InitField(x, y, init_game);
1755 element = Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY;
1756 InitField(x, y, init_game);
1759 case EL_SOKOBAN_FIELD_EMPTY:
1760 local_player->sokobanfields_still_needed++;
1764 if (x < lev_fieldx-1 && Feld[x+1][y] == EL_ACID)
1765 Feld[x][y] = EL_ACID_POOL_TOPLEFT;
1766 else if (x > 0 && Feld[x-1][y] == EL_ACID)
1767 Feld[x][y] = EL_ACID_POOL_TOPRIGHT;
1768 else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPLEFT)
1769 Feld[x][y] = EL_ACID_POOL_BOTTOMLEFT;
1770 else if (y > 0 && Feld[x][y-1] == EL_ACID)
1771 Feld[x][y] = EL_ACID_POOL_BOTTOM;
1772 else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPRIGHT)
1773 Feld[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
1782 case EL_SPACESHIP_RIGHT:
1783 case EL_SPACESHIP_UP:
1784 case EL_SPACESHIP_LEFT:
1785 case EL_SPACESHIP_DOWN:
1786 case EL_BD_BUTTERFLY:
1787 case EL_BD_BUTTERFLY_RIGHT:
1788 case EL_BD_BUTTERFLY_UP:
1789 case EL_BD_BUTTERFLY_LEFT:
1790 case EL_BD_BUTTERFLY_DOWN:
1792 case EL_BD_FIREFLY_RIGHT:
1793 case EL_BD_FIREFLY_UP:
1794 case EL_BD_FIREFLY_LEFT:
1795 case EL_BD_FIREFLY_DOWN:
1796 case EL_PACMAN_RIGHT:
1798 case EL_PACMAN_LEFT:
1799 case EL_PACMAN_DOWN:
1801 case EL_YAMYAM_LEFT:
1802 case EL_YAMYAM_RIGHT:
1804 case EL_YAMYAM_DOWN:
1805 case EL_DARK_YAMYAM:
1808 case EL_SP_SNIKSNAK:
1809 case EL_SP_ELECTRON:
1818 case EL_AMOEBA_FULL:
1823 case EL_AMOEBA_DROP:
1824 if (y == lev_fieldy - 1)
1826 Feld[x][y] = EL_AMOEBA_GROWING;
1827 Store[x][y] = EL_AMOEBA_WET;
1831 case EL_DYNAMITE_ACTIVE:
1832 case EL_SP_DISK_RED_ACTIVE:
1833 case EL_DYNABOMB_PLAYER_1_ACTIVE:
1834 case EL_DYNABOMB_PLAYER_2_ACTIVE:
1835 case EL_DYNABOMB_PLAYER_3_ACTIVE:
1836 case EL_DYNABOMB_PLAYER_4_ACTIVE:
1837 MovDelay[x][y] = 96;
1840 case EL_EM_DYNAMITE_ACTIVE:
1841 MovDelay[x][y] = 32;
1845 local_player->lights_still_needed++;
1849 local_player->friends_still_needed++;
1854 GfxDir[x][y] = MovDir[x][y] = 1 << RND(4);
1857 case EL_CONVEYOR_BELT_1_SWITCH_LEFT:
1858 case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE:
1859 case EL_CONVEYOR_BELT_1_SWITCH_RIGHT:
1860 case EL_CONVEYOR_BELT_2_SWITCH_LEFT:
1861 case EL_CONVEYOR_BELT_2_SWITCH_MIDDLE:
1862 case EL_CONVEYOR_BELT_2_SWITCH_RIGHT:
1863 case EL_CONVEYOR_BELT_3_SWITCH_LEFT:
1864 case EL_CONVEYOR_BELT_3_SWITCH_MIDDLE:
1865 case EL_CONVEYOR_BELT_3_SWITCH_RIGHT:
1866 case EL_CONVEYOR_BELT_4_SWITCH_LEFT:
1867 case EL_CONVEYOR_BELT_4_SWITCH_MIDDLE:
1868 case EL_CONVEYOR_BELT_4_SWITCH_RIGHT:
1871 int belt_nr = getBeltNrFromBeltSwitchElement(Feld[x][y]);
1872 int belt_dir = getBeltDirFromBeltSwitchElement(Feld[x][y]);
1873 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(Feld[x][y]);
1875 if (game.belt_dir_nr[belt_nr] == 3) /* initial value */
1877 game.belt_dir[belt_nr] = belt_dir;
1878 game.belt_dir_nr[belt_nr] = belt_dir_nr;
1880 else /* more than one switch -- set it like the first switch */
1882 Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr];
1887 case EL_LIGHT_SWITCH_ACTIVE:
1889 game.light_time_left = level.time_light * FRAMES_PER_SECOND;
1892 case EL_INVISIBLE_STEELWALL:
1893 case EL_INVISIBLE_WALL:
1894 case EL_INVISIBLE_SAND:
1895 if (game.light_time_left > 0 ||
1896 game.lenses_time_left > 0)
1897 Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
1900 case EL_EMC_MAGIC_BALL:
1901 if (game.ball_state)
1902 Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE;
1905 case EL_EMC_MAGIC_BALL_SWITCH:
1906 if (game.ball_state)
1907 Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE;
1910 case EL_TRIGGER_PLAYER:
1911 case EL_TRIGGER_ELEMENT:
1912 case EL_TRIGGER_CE_VALUE:
1913 case EL_TRIGGER_CE_SCORE:
1915 case EL_ANY_ELEMENT:
1916 case EL_CURRENT_CE_VALUE:
1917 case EL_CURRENT_CE_SCORE:
1934 /* reference elements should not be used on the playfield */
1935 Feld[x][y] = EL_EMPTY;
1939 if (IS_CUSTOM_ELEMENT(element))
1941 if (CAN_MOVE(element))
1944 if (!element_info[element].use_last_ce_value || init_game)
1945 CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]);
1947 else if (IS_GROUP_ELEMENT(element))
1949 Feld[x][y] = GetElementFromGroupElement(element);
1951 InitField(x, y, init_game);
1958 CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X);
1961 inline static void InitField_WithBug1(int x, int y, boolean init_game)
1963 InitField(x, y, init_game);
1965 /* not needed to call InitMovDir() -- already done by InitField()! */
1966 if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
1967 CAN_MOVE(Feld[x][y]))
1971 inline static void InitField_WithBug2(int x, int y, boolean init_game)
1973 int old_element = Feld[x][y];
1975 InitField(x, y, init_game);
1977 /* not needed to call InitMovDir() -- already done by InitField()! */
1978 if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
1979 CAN_MOVE(old_element) &&
1980 (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN))
1983 /* this case is in fact a combination of not less than three bugs:
1984 first, it calls InitMovDir() for elements that can move, although this is
1985 already done by InitField(); then, it checks the element that was at this
1986 field _before_ the call to InitField() (which can change it); lastly, it
1987 was not called for "mole with direction" elements, which were treated as
1988 "cannot move" due to (fixed) wrong element initialization in "src/init.c"
1992 static int get_key_element_from_nr(int key_nr)
1994 int key_base_element = (key_nr >= STD_NUM_KEYS ? EL_EMC_KEY_5 - STD_NUM_KEYS :
1995 level.game_engine_type == GAME_ENGINE_TYPE_EM ?
1996 EL_EM_KEY_1 : EL_KEY_1);
1998 return key_base_element + key_nr;
2001 static int get_next_dropped_element(struct PlayerInfo *player)
2003 return (player->inventory_size > 0 ?
2004 player->inventory_element[player->inventory_size - 1] :
2005 player->inventory_infinite_element != EL_UNDEFINED ?
2006 player->inventory_infinite_element :
2007 player->dynabombs_left > 0 ?
2008 EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr :
2012 static int get_inventory_element_from_pos(struct PlayerInfo *player, int pos)
2014 /* pos >= 0: get element from bottom of the stack;
2015 pos < 0: get element from top of the stack */
2019 int min_inventory_size = -pos;
2020 int inventory_pos = player->inventory_size - min_inventory_size;
2021 int min_dynabombs_left = min_inventory_size - player->inventory_size;
2023 return (player->inventory_size >= min_inventory_size ?
2024 player->inventory_element[inventory_pos] :
2025 player->inventory_infinite_element != EL_UNDEFINED ?
2026 player->inventory_infinite_element :
2027 player->dynabombs_left >= min_dynabombs_left ?
2028 EL_DYNABOMB_PLAYER_1 + player->index_nr :
2033 int min_dynabombs_left = pos + 1;
2034 int min_inventory_size = pos + 1 - player->dynabombs_left;
2035 int inventory_pos = pos - player->dynabombs_left;
2037 return (player->inventory_infinite_element != EL_UNDEFINED ?
2038 player->inventory_infinite_element :
2039 player->dynabombs_left >= min_dynabombs_left ?
2040 EL_DYNABOMB_PLAYER_1 + player->index_nr :
2041 player->inventory_size >= min_inventory_size ?
2042 player->inventory_element[inventory_pos] :
2047 static int compareGamePanelOrderInfo(const void *object1, const void *object2)
2049 const struct GamePanelOrderInfo *gpo1 = (struct GamePanelOrderInfo *)object1;
2050 const struct GamePanelOrderInfo *gpo2 = (struct GamePanelOrderInfo *)object2;
2053 if (gpo1->sort_priority != gpo2->sort_priority)
2054 compare_result = gpo1->sort_priority - gpo2->sort_priority;
2056 compare_result = gpo1->nr - gpo2->nr;
2058 return compare_result;
2061 int getPlayerInventorySize(int player_nr)
2063 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2064 return level.native_em_level->ply[player_nr]->dynamite;
2065 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2066 return level.native_sp_level->game_sp->red_disk_count;
2068 return stored_player[player_nr].inventory_size;
2071 void InitGameControlValues()
2075 for (i = 0; game_panel_controls[i].nr != -1; i++)
2077 struct GamePanelControlInfo *gpc = &game_panel_controls[i];
2078 struct GamePanelOrderInfo *gpo = &game_panel_order[i];
2079 struct TextPosInfo *pos = gpc->pos;
2081 int type = gpc->type;
2085 Error(ERR_INFO, "'game_panel_controls' structure corrupted at %d", i);
2086 Error(ERR_EXIT, "this should not happen -- please debug");
2089 /* force update of game controls after initialization */
2090 gpc->value = gpc->last_value = -1;
2091 gpc->frame = gpc->last_frame = -1;
2092 gpc->gfx_frame = -1;
2094 /* determine panel value width for later calculation of alignment */
2095 if (type == TYPE_INTEGER || type == TYPE_STRING)
2097 pos->width = pos->size * getFontWidth(pos->font);
2098 pos->height = getFontHeight(pos->font);
2100 else if (type == TYPE_ELEMENT)
2102 pos->width = pos->size;
2103 pos->height = pos->size;
2106 /* fill structure for game panel draw order */
2108 gpo->sort_priority = pos->sort_priority;
2111 /* sort game panel controls according to sort_priority and control number */
2112 qsort(game_panel_order, NUM_GAME_PANEL_CONTROLS,
2113 sizeof(struct GamePanelOrderInfo), compareGamePanelOrderInfo);
2116 void UpdatePlayfieldElementCount()
2118 boolean use_element_count = FALSE;
2121 /* first check if it is needed at all to calculate playfield element count */
2122 for (i = GAME_PANEL_ELEMENT_COUNT_1; i <= GAME_PANEL_ELEMENT_COUNT_8; i++)
2123 if (!PANEL_DEACTIVATED(game_panel_controls[i].pos))
2124 use_element_count = TRUE;
2126 if (!use_element_count)
2129 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2130 element_info[i].element_count = 0;
2132 SCAN_PLAYFIELD(x, y)
2134 element_info[Feld[x][y]].element_count++;
2137 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
2138 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2139 if (IS_IN_GROUP(j, i))
2140 element_info[EL_GROUP_START + i].element_count +=
2141 element_info[j].element_count;
2144 void UpdateGameControlValues()
2147 int time = (local_player->LevelSolved ?
2148 local_player->LevelSolved_CountingTime :
2149 level.game_engine_type == GAME_ENGINE_TYPE_EM ?
2150 level.native_em_level->lev->time :
2151 level.game_engine_type == GAME_ENGINE_TYPE_SP ?
2152 level.native_sp_level->game_sp->time_played :
2153 game.no_time_limit ? TimePlayed : TimeLeft);
2154 int score = (local_player->LevelSolved ?
2155 local_player->LevelSolved_CountingScore :
2156 level.game_engine_type == GAME_ENGINE_TYPE_EM ?
2157 level.native_em_level->lev->score :
2158 level.game_engine_type == GAME_ENGINE_TYPE_SP ?
2159 level.native_sp_level->game_sp->score :
2160 local_player->score);
2161 int gems = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
2162 level.native_em_level->lev->required :
2163 level.game_engine_type == GAME_ENGINE_TYPE_SP ?
2164 level.native_sp_level->game_sp->infotrons_still_needed :
2165 local_player->gems_still_needed);
2166 int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
2167 level.native_em_level->lev->required > 0 :
2168 level.game_engine_type == GAME_ENGINE_TYPE_SP ?
2169 level.native_sp_level->game_sp->infotrons_still_needed > 0 :
2170 local_player->gems_still_needed > 0 ||
2171 local_player->sokobanfields_still_needed > 0 ||
2172 local_player->lights_still_needed > 0);
2174 UpdatePlayfieldElementCount();
2176 /* update game panel control values */
2178 game_panel_controls[GAME_PANEL_LEVEL_NUMBER].value = level_nr;
2179 game_panel_controls[GAME_PANEL_GEMS].value = gems;
2181 game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value = 0;
2182 for (i = 0; i < MAX_NUM_KEYS; i++)
2183 game_panel_controls[GAME_PANEL_KEY_1 + i].value = EL_EMPTY;
2184 game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_EMPTY;
2185 game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value = 0;
2187 if (game.centered_player_nr == -1)
2189 for (i = 0; i < MAX_PLAYERS; i++)
2191 /* only one player in Supaplex game engine */
2192 if (level.game_engine_type == GAME_ENGINE_TYPE_SP && i > 0)
2195 for (k = 0; k < MAX_NUM_KEYS; k++)
2197 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2199 if (level.native_em_level->ply[i]->keys & (1 << k))
2200 game_panel_controls[GAME_PANEL_KEY_1 + k].value =
2201 get_key_element_from_nr(k);
2203 else if (stored_player[i].key[k])
2204 game_panel_controls[GAME_PANEL_KEY_1 + k].value =
2205 get_key_element_from_nr(k);
2208 game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value +=
2209 getPlayerInventorySize(i);
2211 if (stored_player[i].num_white_keys > 0)
2212 game_panel_controls[GAME_PANEL_KEY_WHITE].value =
2215 game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value +=
2216 stored_player[i].num_white_keys;
2221 int player_nr = game.centered_player_nr;
2223 for (k = 0; k < MAX_NUM_KEYS; k++)
2225 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2227 if (level.native_em_level->ply[player_nr]->keys & (1 << k))
2228 game_panel_controls[GAME_PANEL_KEY_1 + k].value =
2229 get_key_element_from_nr(k);
2231 else if (stored_player[player_nr].key[k])
2232 game_panel_controls[GAME_PANEL_KEY_1 + k].value =
2233 get_key_element_from_nr(k);
2236 game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value +=
2237 getPlayerInventorySize(player_nr);
2239 if (stored_player[player_nr].num_white_keys > 0)
2240 game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_DC_KEY_WHITE;
2242 game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value +=
2243 stored_player[player_nr].num_white_keys;
2246 for (i = 0; i < NUM_PANEL_INVENTORY; i++)
2248 game_panel_controls[GAME_PANEL_INVENTORY_FIRST_1 + i].value =
2249 get_inventory_element_from_pos(local_player, i);
2250 game_panel_controls[GAME_PANEL_INVENTORY_LAST_1 + i].value =
2251 get_inventory_element_from_pos(local_player, -i - 1);
2254 game_panel_controls[GAME_PANEL_SCORE].value = score;
2255 game_panel_controls[GAME_PANEL_HIGHSCORE].value = highscore[0].Score;
2257 game_panel_controls[GAME_PANEL_TIME].value = time;
2259 game_panel_controls[GAME_PANEL_TIME_HH].value = time / 3600;
2260 game_panel_controls[GAME_PANEL_TIME_MM].value = (time / 60) % 60;
2261 game_panel_controls[GAME_PANEL_TIME_SS].value = time % 60;
2263 game_panel_controls[GAME_PANEL_FRAME].value = FrameCounter;
2265 game_panel_controls[GAME_PANEL_SHIELD_NORMAL].value =
2266 (local_player->shield_normal_time_left > 0 ? EL_SHIELD_NORMAL_ACTIVE :
2268 game_panel_controls[GAME_PANEL_SHIELD_NORMAL_TIME].value =
2269 local_player->shield_normal_time_left;
2270 game_panel_controls[GAME_PANEL_SHIELD_DEADLY].value =
2271 (local_player->shield_deadly_time_left > 0 ? EL_SHIELD_DEADLY_ACTIVE :
2273 game_panel_controls[GAME_PANEL_SHIELD_DEADLY_TIME].value =
2274 local_player->shield_deadly_time_left;
2276 game_panel_controls[GAME_PANEL_EXIT].value =
2277 (exit_closed ? EL_EXIT_CLOSED : EL_EXIT_OPEN);
2279 game_panel_controls[GAME_PANEL_EMC_MAGIC_BALL].value =
2280 (game.ball_state ? EL_EMC_MAGIC_BALL_ACTIVE : EL_EMC_MAGIC_BALL);
2281 game_panel_controls[GAME_PANEL_EMC_MAGIC_BALL_SWITCH].value =
2282 (game.ball_state ? EL_EMC_MAGIC_BALL_SWITCH_ACTIVE :
2283 EL_EMC_MAGIC_BALL_SWITCH);
2285 game_panel_controls[GAME_PANEL_LIGHT_SWITCH].value =
2286 (game.light_time_left > 0 ? EL_LIGHT_SWITCH_ACTIVE : EL_LIGHT_SWITCH);
2287 game_panel_controls[GAME_PANEL_LIGHT_SWITCH_TIME].value =
2288 game.light_time_left;
2290 game_panel_controls[GAME_PANEL_TIMEGATE_SWITCH].value =
2291 (game.timegate_time_left > 0 ? EL_TIMEGATE_OPEN : EL_TIMEGATE_CLOSED);
2292 game_panel_controls[GAME_PANEL_TIMEGATE_SWITCH_TIME].value =
2293 game.timegate_time_left;
2295 game_panel_controls[GAME_PANEL_SWITCHGATE_SWITCH].value =
2296 EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos;
2298 game_panel_controls[GAME_PANEL_EMC_LENSES].value =
2299 (game.lenses_time_left > 0 ? EL_EMC_LENSES : EL_EMPTY);
2300 game_panel_controls[GAME_PANEL_EMC_LENSES_TIME].value =
2301 game.lenses_time_left;
2303 game_panel_controls[GAME_PANEL_EMC_MAGNIFIER].value =
2304 (game.magnify_time_left > 0 ? EL_EMC_MAGNIFIER : EL_EMPTY);
2305 game_panel_controls[GAME_PANEL_EMC_MAGNIFIER_TIME].value =
2306 game.magnify_time_left;
2308 game_panel_controls[GAME_PANEL_BALLOON_SWITCH].value =
2309 (game.wind_direction == MV_LEFT ? EL_BALLOON_SWITCH_LEFT :
2310 game.wind_direction == MV_RIGHT ? EL_BALLOON_SWITCH_RIGHT :
2311 game.wind_direction == MV_UP ? EL_BALLOON_SWITCH_UP :
2312 game.wind_direction == MV_DOWN ? EL_BALLOON_SWITCH_DOWN :
2313 EL_BALLOON_SWITCH_NONE);
2315 game_panel_controls[GAME_PANEL_DYNABOMB_NUMBER].value =
2316 local_player->dynabomb_count;
2317 game_panel_controls[GAME_PANEL_DYNABOMB_SIZE].value =
2318 local_player->dynabomb_size;
2319 game_panel_controls[GAME_PANEL_DYNABOMB_POWER].value =
2320 (local_player->dynabomb_xl ? EL_DYNABOMB_INCREASE_POWER : EL_EMPTY);
2322 game_panel_controls[GAME_PANEL_PENGUINS].value =
2323 local_player->friends_still_needed;
2325 game_panel_controls[GAME_PANEL_SOKOBAN_OBJECTS].value =
2326 local_player->sokobanfields_still_needed;
2327 game_panel_controls[GAME_PANEL_SOKOBAN_FIELDS].value =
2328 local_player->sokobanfields_still_needed;
2330 game_panel_controls[GAME_PANEL_ROBOT_WHEEL].value =
2331 (game.robot_wheel_active ? EL_ROBOT_WHEEL_ACTIVE : EL_ROBOT_WHEEL);
2333 for (i = 0; i < NUM_BELTS; i++)
2335 game_panel_controls[GAME_PANEL_CONVEYOR_BELT_1 + i].value =
2336 (game.belt_dir[i] != MV_NONE ? EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE :
2337 EL_CONVEYOR_BELT_1_MIDDLE) + i;
2338 game_panel_controls[GAME_PANEL_CONVEYOR_BELT_1_SWITCH + i].value =
2339 getBeltSwitchElementFromBeltNrAndBeltDir(i, game.belt_dir[i]);
2342 game_panel_controls[GAME_PANEL_MAGIC_WALL].value =
2343 (game.magic_wall_active ? EL_MAGIC_WALL_ACTIVE : EL_MAGIC_WALL);
2344 game_panel_controls[GAME_PANEL_MAGIC_WALL_TIME].value =
2345 game.magic_wall_time_left;
2347 game_panel_controls[GAME_PANEL_GRAVITY_STATE].value =
2348 local_player->gravity;
2350 for (i = 0; i < NUM_PANEL_GRAPHICS; i++)
2351 game_panel_controls[GAME_PANEL_GRAPHIC_1 + i].value = EL_GRAPHIC_1 + i;
2353 for (i = 0; i < NUM_PANEL_ELEMENTS; i++)
2354 game_panel_controls[GAME_PANEL_ELEMENT_1 + i].value =
2355 (IS_DRAWABLE_ELEMENT(game.panel.element[i].id) ?
2356 game.panel.element[i].id : EL_UNDEFINED);
2358 for (i = 0; i < NUM_PANEL_ELEMENTS; i++)
2359 game_panel_controls[GAME_PANEL_ELEMENT_COUNT_1 + i].value =
2360 (IS_VALID_ELEMENT(game.panel.element_count[i].id) ?
2361 element_info[game.panel.element_count[i].id].element_count : 0);
2363 for (i = 0; i < NUM_PANEL_CE_SCORE; i++)
2364 game_panel_controls[GAME_PANEL_CE_SCORE_1 + i].value =
2365 (IS_CUSTOM_ELEMENT(game.panel.ce_score[i].id) ?
2366 element_info[game.panel.ce_score[i].id].collect_score : 0);
2368 for (i = 0; i < NUM_PANEL_CE_SCORE; i++)
2369 game_panel_controls[GAME_PANEL_CE_SCORE_1_ELEMENT + i].value =
2370 (IS_CUSTOM_ELEMENT(game.panel.ce_score_element[i].id) ?
2371 element_info[game.panel.ce_score_element[i].id].collect_score :
2374 game_panel_controls[GAME_PANEL_PLAYER_NAME].value = 0;
2375 game_panel_controls[GAME_PANEL_LEVEL_NAME].value = 0;
2376 game_panel_controls[GAME_PANEL_LEVEL_AUTHOR].value = 0;
2378 /* update game panel control frames */
2380 for (i = 0; game_panel_controls[i].nr != -1; i++)
2382 struct GamePanelControlInfo *gpc = &game_panel_controls[i];
2384 if (gpc->type == TYPE_ELEMENT)
2386 if (gpc->value != EL_UNDEFINED && gpc->value != EL_EMPTY)
2388 int last_anim_random_frame = gfx.anim_random_frame;
2389 int element = gpc->value;
2390 int graphic = el2panelimg(element);
2392 if (gpc->value != gpc->last_value)
2395 gpc->gfx_random = INIT_GFX_RANDOM();
2401 if (ANIM_MODE(graphic) == ANIM_RANDOM &&
2402 IS_NEXT_FRAME(gpc->gfx_frame, graphic))
2403 gpc->gfx_random = INIT_GFX_RANDOM();
2406 if (ANIM_MODE(graphic) == ANIM_RANDOM)
2407 gfx.anim_random_frame = gpc->gfx_random;
2409 if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
2410 gpc->gfx_frame = element_info[element].collect_score;
2412 gpc->frame = getGraphicAnimationFrame(el2panelimg(gpc->value),
2415 if (ANIM_MODE(graphic) == ANIM_RANDOM)
2416 gfx.anim_random_frame = last_anim_random_frame;
2422 void DisplayGameControlValues()
2424 boolean redraw_panel = FALSE;
2427 for (i = 0; game_panel_controls[i].nr != -1; i++)
2429 struct GamePanelControlInfo *gpc = &game_panel_controls[i];
2431 if (PANEL_DEACTIVATED(gpc->pos))
2434 if (gpc->value == gpc->last_value &&
2435 gpc->frame == gpc->last_frame)
2438 redraw_panel = TRUE;
2444 /* copy default game door content to main double buffer */
2446 /* !!! CHECK AGAIN !!! */
2447 SetPanelBackground();
2448 // SetDoorBackgroundImage(IMG_BACKGROUND_PANEL);
2449 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2451 /* redraw game control buttons */
2452 RedrawGameButtons();
2454 SetGameStatus(GAME_MODE_PSEUDO_PANEL);
2456 for (i = 0; i < NUM_GAME_PANEL_CONTROLS; i++)
2458 int nr = game_panel_order[i].nr;
2459 struct GamePanelControlInfo *gpc = &game_panel_controls[nr];
2460 struct TextPosInfo *pos = gpc->pos;
2461 int type = gpc->type;
2462 int value = gpc->value;
2463 int frame = gpc->frame;
2464 int size = pos->size;
2465 int font = pos->font;
2466 boolean draw_masked = pos->draw_masked;
2467 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_OPAQUE);
2469 if (PANEL_DEACTIVATED(pos))
2472 gpc->last_value = value;
2473 gpc->last_frame = frame;
2475 if (type == TYPE_INTEGER)
2477 if (nr == GAME_PANEL_LEVEL_NUMBER ||
2478 nr == GAME_PANEL_TIME)
2480 boolean use_dynamic_size = (size == -1 ? TRUE : FALSE);
2482 if (use_dynamic_size) /* use dynamic number of digits */
2484 int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 : 1000);
2485 int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 : 3);
2486 int size2 = size1 + 1;
2487 int font1 = pos->font;
2488 int font2 = pos->font_alt;
2490 size = (value < value_change ? size1 : size2);
2491 font = (value < value_change ? font1 : font2);
2495 /* correct text size if "digits" is zero or less */
2497 size = strlen(int2str(value, size));
2499 /* dynamically correct text alignment */
2500 pos->width = size * getFontWidth(font);
2502 DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos),
2503 int2str(value, size), font, mask_mode);
2505 else if (type == TYPE_ELEMENT)
2507 int element, graphic;
2511 int dst_x = PANEL_XPOS(pos);
2512 int dst_y = PANEL_YPOS(pos);
2514 if (value != EL_UNDEFINED && value != EL_EMPTY)
2517 graphic = el2panelimg(value);
2519 // printf("::: %d, '%s' [%d]\n", element, EL_NAME(element), size);
2521 if (element >= EL_GRAPHIC_1 && element <= EL_GRAPHIC_8 && size == 0)
2524 getSizedGraphicSource(graphic, frame, size, &src_bitmap,
2527 width = graphic_info[graphic].width * size / TILESIZE;
2528 height = graphic_info[graphic].height * size / TILESIZE;
2531 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height,
2534 BlitBitmap(src_bitmap, drawto, src_x, src_y, width, height,
2538 else if (type == TYPE_STRING)
2540 boolean active = (value != 0);
2541 char *state_normal = "off";
2542 char *state_active = "on";
2543 char *state = (active ? state_active : state_normal);
2544 char *s = (nr == GAME_PANEL_GRAVITY_STATE ? state :
2545 nr == GAME_PANEL_PLAYER_NAME ? setup.player_name :
2546 nr == GAME_PANEL_LEVEL_NAME ? level.name :
2547 nr == GAME_PANEL_LEVEL_AUTHOR ? level.author : NULL);
2549 if (nr == GAME_PANEL_GRAVITY_STATE)
2551 int font1 = pos->font; /* (used for normal state) */
2552 int font2 = pos->font_alt; /* (used for active state) */
2554 font = (active ? font2 : font1);
2563 /* don't truncate output if "chars" is zero or less */
2566 /* dynamically correct text alignment */
2567 pos->width = size * getFontWidth(font);
2570 s_cut = getStringCopyN(s, size);
2572 DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos),
2573 s_cut, font, mask_mode);
2579 redraw_mask |= REDRAW_DOOR_1;
2582 SetGameStatus(GAME_MODE_PLAYING);
2585 void UpdateAndDisplayGameControlValues()
2587 if (tape.deactivate_display)
2590 UpdateGameControlValues();
2591 DisplayGameControlValues();
2594 void UpdateGameDoorValues()
2596 UpdateGameControlValues();
2599 void DrawGameDoorValues()
2601 DisplayGameControlValues();
2606 =============================================================================
2608 -----------------------------------------------------------------------------
2609 initialize game engine due to level / tape version number
2610 =============================================================================
2613 static void InitGameEngine()
2615 int i, j, k, l, x, y;
2617 /* set game engine from tape file when re-playing, else from level file */
2618 game.engine_version = (tape.playing ? tape.engine_version :
2619 level.game_version);
2621 /* set single or multi-player game mode (needed for re-playing tapes) */
2622 game.team_mode = setup.team_mode;
2626 int num_players = 0;
2628 for (i = 0; i < MAX_PLAYERS; i++)
2629 if (tape.player_participates[i])
2632 /* multi-player tapes contain input data for more than one player */
2633 game.team_mode = (num_players > 1);
2636 /* ---------------------------------------------------------------------- */
2637 /* set flags for bugs and changes according to active game engine version */
2638 /* ---------------------------------------------------------------------- */
2641 Summary of bugfix/change:
2642 Fixed handling for custom elements that change when pushed by the player.
2644 Fixed/changed in version:
2648 Before 3.1.0, custom elements that "change when pushing" changed directly
2649 after the player started pushing them (until then handled in "DigField()").
2650 Since 3.1.0, these custom elements are not changed until the "pushing"
2651 move of the element is finished (now handled in "ContinueMoving()").
2653 Affected levels/tapes:
2654 The first condition is generally needed for all levels/tapes before version
2655 3.1.0, which might use the old behaviour before it was changed; known tapes
2656 that are affected are some tapes from the level set "Walpurgis Gardens" by
2658 The second condition is an exception from the above case and is needed for
2659 the special case of tapes recorded with game (not engine!) version 3.1.0 or
2660 above (including some development versions of 3.1.0), but before it was
2661 known that this change would break tapes like the above and was fixed in
2662 3.1.1, so that the changed behaviour was active although the engine version
2663 while recording maybe was before 3.1.0. There is at least one tape that is
2664 affected by this exception, which is the tape for the one-level set "Bug
2665 Machine" by Juergen Bonhagen.
2668 game.use_change_when_pushing_bug =
2669 (game.engine_version < VERSION_IDENT(3,1,0,0) &&
2671 tape.game_version >= VERSION_IDENT(3,1,0,0) &&
2672 tape.game_version < VERSION_IDENT(3,1,1,0)));
2675 Summary of bugfix/change:
2676 Fixed handling for blocking the field the player leaves when moving.
2678 Fixed/changed in version:
2682 Before 3.1.1, when "block last field when moving" was enabled, the field
2683 the player is leaving when moving was blocked for the time of the move,
2684 and was directly unblocked afterwards. This resulted in the last field
2685 being blocked for exactly one less than the number of frames of one player
2686 move. Additionally, even when blocking was disabled, the last field was
2687 blocked for exactly one frame.
2688 Since 3.1.1, due to changes in player movement handling, the last field
2689 is not blocked at all when blocking is disabled. When blocking is enabled,
2690 the last field is blocked for exactly the number of frames of one player
2691 move. Additionally, if the player is Murphy, the hero of Supaplex, the
2692 last field is blocked for exactly one more than the number of frames of
2695 Affected levels/tapes:
2696 (!!! yet to be determined -- probably many !!!)
2699 game.use_block_last_field_bug =
2700 (game.engine_version < VERSION_IDENT(3,1,1,0));
2702 /* ---------------------------------------------------------------------- */
2704 /* set maximal allowed number of custom element changes per game frame */
2705 game.max_num_changes_per_frame = 1;
2707 /* default scan direction: scan playfield from top/left to bottom/right */
2708 InitPlayfieldScanMode(CA_ARG_SCAN_MODE_NORMAL);
2710 /* dynamically adjust element properties according to game engine version */
2711 InitElementPropertiesEngine(game.engine_version);
2714 printf("level %d: level version == %06d\n", level_nr, level.game_version);
2715 printf(" tape version == %06d [%s] [file: %06d]\n",
2716 tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"),
2718 printf(" => game.engine_version == %06d\n", game.engine_version);
2721 /* ---------- initialize player's initial move delay --------------------- */
2723 /* dynamically adjust player properties according to level information */
2724 for (i = 0; i < MAX_PLAYERS; i++)
2725 game.initial_move_delay_value[i] =
2726 get_move_delay_from_stepsize(level.initial_player_stepsize[i]);
2728 /* dynamically adjust player properties according to game engine version */
2729 for (i = 0; i < MAX_PLAYERS; i++)
2730 game.initial_move_delay[i] =
2731 (game.engine_version <= VERSION_IDENT(2,0,1,0) ?
2732 game.initial_move_delay_value[i] : 0);
2734 /* ---------- initialize player's initial push delay --------------------- */
2736 /* dynamically adjust player properties according to game engine version */
2737 game.initial_push_delay_value =
2738 (game.engine_version < VERSION_IDENT(3,0,7,1) ? 5 : -1);
2740 /* ---------- initialize changing elements ------------------------------- */
2742 /* initialize changing elements information */
2743 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2745 struct ElementInfo *ei = &element_info[i];
2747 /* this pointer might have been changed in the level editor */
2748 ei->change = &ei->change_page[0];
2750 if (!IS_CUSTOM_ELEMENT(i))
2752 ei->change->target_element = EL_EMPTY_SPACE;
2753 ei->change->delay_fixed = 0;
2754 ei->change->delay_random = 0;
2755 ei->change->delay_frames = 1;
2758 for (j = 0; j < NUM_CHANGE_EVENTS; j++)
2760 ei->has_change_event[j] = FALSE;
2762 ei->event_page_nr[j] = 0;
2763 ei->event_page[j] = &ei->change_page[0];
2767 /* add changing elements from pre-defined list */
2768 for (i = 0; change_delay_list[i].element != EL_UNDEFINED; i++)
2770 struct ChangingElementInfo *ch_delay = &change_delay_list[i];
2771 struct ElementInfo *ei = &element_info[ch_delay->element];
2773 ei->change->target_element = ch_delay->target_element;
2774 ei->change->delay_fixed = ch_delay->change_delay;
2776 ei->change->pre_change_function = ch_delay->pre_change_function;
2777 ei->change->change_function = ch_delay->change_function;
2778 ei->change->post_change_function = ch_delay->post_change_function;
2780 ei->change->can_change = TRUE;
2781 ei->change->can_change_or_has_action = TRUE;
2783 ei->has_change_event[CE_DELAY] = TRUE;
2785 SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE);
2786 SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE);
2789 /* ---------- initialize internal run-time variables --------------------- */
2791 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
2793 struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
2795 for (j = 0; j < ei->num_change_pages; j++)
2797 ei->change_page[j].can_change_or_has_action =
2798 (ei->change_page[j].can_change |
2799 ei->change_page[j].has_action);
2803 /* add change events from custom element configuration */
2804 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
2806 struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
2808 for (j = 0; j < ei->num_change_pages; j++)
2810 if (!ei->change_page[j].can_change_or_has_action)
2813 for (k = 0; k < NUM_CHANGE_EVENTS; k++)
2815 /* only add event page for the first page found with this event */
2816 if (ei->change_page[j].has_event[k] && !(ei->has_change_event[k]))
2818 ei->has_change_event[k] = TRUE;
2820 ei->event_page_nr[k] = j;
2821 ei->event_page[k] = &ei->change_page[j];
2827 /* ---------- initialize reference elements in change conditions --------- */
2829 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
2831 int element = EL_CUSTOM_START + i;
2832 struct ElementInfo *ei = &element_info[element];
2834 for (j = 0; j < ei->num_change_pages; j++)
2836 int trigger_element = ei->change_page[j].initial_trigger_element;
2838 if (trigger_element >= EL_PREV_CE_8 &&
2839 trigger_element <= EL_NEXT_CE_8)
2840 trigger_element = RESOLVED_REFERENCE_ELEMENT(element, trigger_element);
2842 ei->change_page[j].trigger_element = trigger_element;
2846 /* ---------- initialize run-time trigger player and element ------------- */
2848 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
2850 struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
2852 for (j = 0; j < ei->num_change_pages; j++)
2854 ei->change_page[j].actual_trigger_element = EL_EMPTY;
2855 ei->change_page[j].actual_trigger_player = EL_EMPTY;
2856 ei->change_page[j].actual_trigger_player_bits = CH_PLAYER_NONE;
2857 ei->change_page[j].actual_trigger_side = CH_SIDE_NONE;
2858 ei->change_page[j].actual_trigger_ce_value = 0;
2859 ei->change_page[j].actual_trigger_ce_score = 0;
2863 /* ---------- initialize trigger events ---------------------------------- */
2865 /* initialize trigger events information */
2866 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2867 for (j = 0; j < NUM_CHANGE_EVENTS; j++)
2868 trigger_events[i][j] = FALSE;
2870 /* add trigger events from element change event properties */
2871 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2873 struct ElementInfo *ei = &element_info[i];
2875 for (j = 0; j < ei->num_change_pages; j++)
2877 if (!ei->change_page[j].can_change_or_has_action)
2880 if (ei->change_page[j].has_event[CE_BY_OTHER_ACTION])
2882 int trigger_element = ei->change_page[j].trigger_element;
2884 for (k = 0; k < NUM_CHANGE_EVENTS; k++)
2886 if (ei->change_page[j].has_event[k])
2888 if (IS_GROUP_ELEMENT(trigger_element))
2890 struct ElementGroupInfo *group =
2891 element_info[trigger_element].group;
2893 for (l = 0; l < group->num_elements_resolved; l++)
2894 trigger_events[group->element_resolved[l]][k] = TRUE;
2896 else if (trigger_element == EL_ANY_ELEMENT)
2897 for (l = 0; l < MAX_NUM_ELEMENTS; l++)
2898 trigger_events[l][k] = TRUE;
2900 trigger_events[trigger_element][k] = TRUE;
2907 /* ---------- initialize push delay -------------------------------------- */
2909 /* initialize push delay values to default */
2910 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2912 if (!IS_CUSTOM_ELEMENT(i))
2914 /* set default push delay values (corrected since version 3.0.7-1) */
2915 if (game.engine_version < VERSION_IDENT(3,0,7,1))
2917 element_info[i].push_delay_fixed = 2;
2918 element_info[i].push_delay_random = 8;
2922 element_info[i].push_delay_fixed = 8;
2923 element_info[i].push_delay_random = 8;
2928 /* set push delay value for certain elements from pre-defined list */
2929 for (i = 0; push_delay_list[i].element != EL_UNDEFINED; i++)
2931 int e = push_delay_list[i].element;
2933 element_info[e].push_delay_fixed = push_delay_list[i].push_delay_fixed;
2934 element_info[e].push_delay_random = push_delay_list[i].push_delay_random;
2937 /* set push delay value for Supaplex elements for newer engine versions */
2938 if (game.engine_version >= VERSION_IDENT(3,1,0,0))
2940 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2942 if (IS_SP_ELEMENT(i))
2944 /* set SP push delay to just enough to push under a falling zonk */
2945 int delay = (game.engine_version >= VERSION_IDENT(3,1,1,0) ? 8 : 6);
2947 element_info[i].push_delay_fixed = delay;
2948 element_info[i].push_delay_random = 0;
2953 /* ---------- initialize move stepsize ----------------------------------- */
2955 /* initialize move stepsize values to default */
2956 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2957 if (!IS_CUSTOM_ELEMENT(i))
2958 element_info[i].move_stepsize = MOVE_STEPSIZE_NORMAL;
2960 /* set move stepsize value for certain elements from pre-defined list */
2961 for (i = 0; move_stepsize_list[i].element != EL_UNDEFINED; i++)
2963 int e = move_stepsize_list[i].element;
2965 element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize;
2968 /* ---------- initialize collect score ----------------------------------- */
2970 /* initialize collect score values for custom elements from initial value */
2971 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2972 if (IS_CUSTOM_ELEMENT(i))
2973 element_info[i].collect_score = element_info[i].collect_score_initial;
2975 /* ---------- initialize collect count ----------------------------------- */
2977 /* initialize collect count values for non-custom elements */
2978 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2979 if (!IS_CUSTOM_ELEMENT(i))
2980 element_info[i].collect_count_initial = 0;
2982 /* add collect count values for all elements from pre-defined list */
2983 for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++)
2984 element_info[collect_count_list[i].element].collect_count_initial =
2985 collect_count_list[i].count;
2987 /* ---------- initialize access direction -------------------------------- */
2989 /* initialize access direction values to default (access from every side) */
2990 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2991 if (!IS_CUSTOM_ELEMENT(i))
2992 element_info[i].access_direction = MV_ALL_DIRECTIONS;
2994 /* set access direction value for certain elements from pre-defined list */
2995 for (i = 0; access_direction_list[i].element != EL_UNDEFINED; i++)
2996 element_info[access_direction_list[i].element].access_direction =
2997 access_direction_list[i].direction;
2999 /* ---------- initialize explosion content ------------------------------- */
3000 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3002 if (IS_CUSTOM_ELEMENT(i))
3005 for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
3007 /* (content for EL_YAMYAM set at run-time with game.yamyam_content_nr) */
3009 element_info[i].content.e[x][y] =
3010 (i == EL_PLAYER_1 ? EL_EMERALD_YELLOW :
3011 i == EL_PLAYER_2 ? EL_EMERALD_RED :
3012 i == EL_PLAYER_3 ? EL_EMERALD :
3013 i == EL_PLAYER_4 ? EL_EMERALD_PURPLE :
3014 i == EL_MOLE ? EL_EMERALD_RED :
3015 i == EL_PENGUIN ? EL_EMERALD_PURPLE :
3016 i == EL_BUG ? (x == 1 && y == 1 ? EL_DIAMOND : EL_EMERALD) :
3017 i == EL_BD_BUTTERFLY ? EL_BD_DIAMOND :
3018 i == EL_SP_ELECTRON ? EL_SP_INFOTRON :
3019 i == EL_AMOEBA_TO_DIAMOND ? level.amoeba_content :
3020 i == EL_WALL_EMERALD ? EL_EMERALD :
3021 i == EL_WALL_DIAMOND ? EL_DIAMOND :
3022 i == EL_WALL_BD_DIAMOND ? EL_BD_DIAMOND :
3023 i == EL_WALL_EMERALD_YELLOW ? EL_EMERALD_YELLOW :
3024 i == EL_WALL_EMERALD_RED ? EL_EMERALD_RED :
3025 i == EL_WALL_EMERALD_PURPLE ? EL_EMERALD_PURPLE :
3026 i == EL_WALL_PEARL ? EL_PEARL :
3027 i == EL_WALL_CRYSTAL ? EL_CRYSTAL :
3032 /* ---------- initialize recursion detection ------------------------------ */
3033 recursion_loop_depth = 0;
3034 recursion_loop_detected = FALSE;
3035 recursion_loop_element = EL_UNDEFINED;
3037 /* ---------- initialize graphics engine ---------------------------------- */
3038 game.scroll_delay_value =
3039 (game.forced_scroll_delay_value != -1 ? game.forced_scroll_delay_value :
3040 setup.scroll_delay ? setup.scroll_delay_value : 0);
3041 game.scroll_delay_value =
3042 MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY);
3044 /* ---------- initialize game engine snapshots ---------------------------- */
3045 for (i = 0; i < MAX_PLAYERS; i++)
3046 game.snapshot.last_action[i] = 0;
3047 game.snapshot.changed_action = FALSE;
3048 game.snapshot.collected_item = FALSE;
3049 game.snapshot.mode =
3050 (strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_STEP) ?
3051 SNAPSHOT_MODE_EVERY_STEP :
3052 strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_MOVE) ?
3053 SNAPSHOT_MODE_EVERY_MOVE :
3054 strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_COLLECT) ?
3055 SNAPSHOT_MODE_EVERY_COLLECT : SNAPSHOT_MODE_OFF);
3056 game.snapshot.save_snapshot = FALSE;
3059 int get_num_special_action(int element, int action_first, int action_last)
3061 int num_special_action = 0;
3064 for (i = action_first; i <= action_last; i++)
3066 boolean found = FALSE;
3068 for (j = 0; j < NUM_DIRECTIONS; j++)
3069 if (el_act_dir2img(element, i, j) !=
3070 el_act_dir2img(element, ACTION_DEFAULT, j))
3074 num_special_action++;
3079 return num_special_action;
3084 =============================================================================
3086 -----------------------------------------------------------------------------
3087 initialize and start new game
3088 =============================================================================
3093 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
3094 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
3095 int fade_mask = REDRAW_FIELD;
3097 boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */
3098 boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */
3099 boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */
3100 int initial_move_dir = MV_DOWN;
3103 // required here to update video display before fading (FIX THIS)
3104 DrawMaskedBorder(REDRAW_DOOR_2);
3106 if (!game.restart_level)
3107 CloseDoor(DOOR_CLOSE_1);
3109 SetGameStatus(GAME_MODE_PLAYING);
3111 if (level_editor_test_game)
3112 FadeSkipNextFadeIn();
3114 FadeSetEnterScreen();
3116 if (CheckIfGlobalBorderHasChanged())
3117 fade_mask = REDRAW_ALL;
3119 FadeSoundsAndMusic();
3121 ExpireSoundLoops(TRUE);
3125 /* needed if different viewport properties defined for playing */
3126 ChangeViewportPropertiesIfNeeded();
3130 OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
3132 DrawCompleteVideoDisplay();
3135 InitGameControlValues();
3137 /* don't play tapes over network */
3138 network_playing = (options.network && !tape.playing);
3140 for (i = 0; i < MAX_PLAYERS; i++)
3142 struct PlayerInfo *player = &stored_player[i];
3144 player->index_nr = i;
3145 player->index_bit = (1 << i);
3146 player->element_nr = EL_PLAYER_1 + i;
3148 player->present = FALSE;
3149 player->active = FALSE;
3150 player->mapped = FALSE;
3152 player->killed = FALSE;
3153 player->reanimated = FALSE;
3156 player->effective_action = 0;
3157 player->programmed_action = 0;
3160 player->score_final = 0;
3162 player->gems_still_needed = level.gems_needed;
3163 player->sokobanfields_still_needed = 0;
3164 player->lights_still_needed = 0;
3165 player->friends_still_needed = 0;
3167 for (j = 0; j < MAX_NUM_KEYS; j++)
3168 player->key[j] = FALSE;
3170 player->num_white_keys = 0;
3172 player->dynabomb_count = 0;
3173 player->dynabomb_size = 1;
3174 player->dynabombs_left = 0;
3175 player->dynabomb_xl = FALSE;
3177 player->MovDir = initial_move_dir;
3180 player->GfxDir = initial_move_dir;
3181 player->GfxAction = ACTION_DEFAULT;
3183 player->StepFrame = 0;
3185 player->initial_element = player->element_nr;
3186 player->artwork_element =
3187 (level.use_artwork_element[i] ? level.artwork_element[i] :
3188 player->element_nr);
3189 player->use_murphy = FALSE;
3191 player->block_last_field = FALSE; /* initialized in InitPlayerField() */
3192 player->block_delay_adjustment = 0; /* initialized in InitPlayerField() */
3194 player->gravity = level.initial_player_gravity[i];
3196 player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr);
3198 player->actual_frame_counter = 0;
3200 player->step_counter = 0;
3202 player->last_move_dir = initial_move_dir;
3204 player->is_active = FALSE;
3206 player->is_waiting = FALSE;
3207 player->is_moving = FALSE;
3208 player->is_auto_moving = FALSE;
3209 player->is_digging = FALSE;
3210 player->is_snapping = FALSE;
3211 player->is_collecting = FALSE;
3212 player->is_pushing = FALSE;
3213 player->is_switching = FALSE;
3214 player->is_dropping = FALSE;
3215 player->is_dropping_pressed = FALSE;
3217 player->is_bored = FALSE;
3218 player->is_sleeping = FALSE;
3220 player->was_waiting = TRUE;
3221 player->was_moving = FALSE;
3222 player->was_snapping = FALSE;
3223 player->was_dropping = FALSE;
3225 player->frame_counter_bored = -1;
3226 player->frame_counter_sleeping = -1;
3228 player->anim_delay_counter = 0;
3229 player->post_delay_counter = 0;
3231 player->dir_waiting = initial_move_dir;
3232 player->action_waiting = ACTION_DEFAULT;
3233 player->last_action_waiting = ACTION_DEFAULT;
3234 player->special_action_bored = ACTION_DEFAULT;
3235 player->special_action_sleeping = ACTION_DEFAULT;
3237 player->switch_x = -1;
3238 player->switch_y = -1;
3240 player->drop_x = -1;
3241 player->drop_y = -1;
3243 player->show_envelope = 0;
3245 SetPlayerMoveSpeed(player, level.initial_player_stepsize[i], TRUE);
3247 player->push_delay = -1; /* initialized when pushing starts */
3248 player->push_delay_value = game.initial_push_delay_value;
3250 player->drop_delay = 0;
3251 player->drop_pressed_delay = 0;
3253 player->last_jx = -1;
3254 player->last_jy = -1;
3258 player->shield_normal_time_left = 0;
3259 player->shield_deadly_time_left = 0;
3261 player->inventory_infinite_element = EL_UNDEFINED;
3262 player->inventory_size = 0;
3264 if (level.use_initial_inventory[i])
3266 for (j = 0; j < level.initial_inventory_size[i]; j++)
3268 int element = level.initial_inventory_content[i][j];
3269 int collect_count = element_info[element].collect_count_initial;
3272 if (!IS_CUSTOM_ELEMENT(element))
3275 if (collect_count == 0)
3276 player->inventory_infinite_element = element;
3278 for (k = 0; k < collect_count; k++)
3279 if (player->inventory_size < MAX_INVENTORY_SIZE)
3280 player->inventory_element[player->inventory_size++] = element;
3284 DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
3285 SnapField(player, 0, 0);
3287 player->LevelSolved = FALSE;
3288 player->GameOver = FALSE;
3290 player->LevelSolved_GameWon = FALSE;
3291 player->LevelSolved_GameEnd = FALSE;
3292 player->LevelSolved_PanelOff = FALSE;
3293 player->LevelSolved_SaveTape = FALSE;
3294 player->LevelSolved_SaveScore = FALSE;
3295 player->LevelSolved_CountingTime = 0;
3296 player->LevelSolved_CountingScore = 0;
3298 map_player_action[i] = i;
3301 network_player_action_received = FALSE;
3303 #if defined(NETWORK_AVALIABLE)
3304 /* initial null action */
3305 if (network_playing)
3306 SendToServer_MovePlayer(MV_NONE);
3315 TimeLeft = level.time;
3318 ScreenMovDir = MV_NONE;
3322 ScrollStepSize = 0; /* will be correctly initialized by ScrollScreen() */
3324 AllPlayersGone = FALSE;
3326 game.no_time_limit = (level.time == 0);
3328 game.yamyam_content_nr = 0;
3329 game.robot_wheel_active = FALSE;
3330 game.magic_wall_active = FALSE;
3331 game.magic_wall_time_left = 0;
3332 game.light_time_left = 0;
3333 game.timegate_time_left = 0;
3334 game.switchgate_pos = 0;
3335 game.wind_direction = level.wind_direction_initial;
3337 game.lenses_time_left = 0;
3338 game.magnify_time_left = 0;
3340 game.ball_state = level.ball_state_initial;
3341 game.ball_content_nr = 0;
3343 game.envelope_active = FALSE;
3345 /* set focus to local player for network games, else to all players */
3346 game.centered_player_nr = (network_playing ? local_player->index_nr : -1);
3347 game.centered_player_nr_next = game.centered_player_nr;
3348 game.set_centered_player = FALSE;
3350 if (network_playing && tape.recording)
3352 /* store client dependent player focus when recording network games */
3353 tape.centered_player_nr_next = game.centered_player_nr_next;
3354 tape.set_centered_player = TRUE;
3357 for (i = 0; i < NUM_BELTS; i++)
3359 game.belt_dir[i] = MV_NONE;
3360 game.belt_dir_nr[i] = 3; /* not moving, next moving left */
3363 for (i = 0; i < MAX_NUM_AMOEBA; i++)
3364 AmoebaCnt[i] = AmoebaCnt2[i] = 0;
3366 #if DEBUG_INIT_PLAYER
3369 printf("Player status at level initialization:\n");
3373 SCAN_PLAYFIELD(x, y)
3375 Feld[x][y] = level.field[x][y];
3376 MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
3377 ChangeDelay[x][y] = 0;
3378 ChangePage[x][y] = -1;
3379 CustomValue[x][y] = 0; /* initialized in InitField() */
3380 Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
3382 WasJustMoving[x][y] = 0;
3383 WasJustFalling[x][y] = 0;
3384 CheckCollision[x][y] = 0;
3385 CheckImpact[x][y] = 0;
3387 Pushed[x][y] = FALSE;
3389 ChangeCount[x][y] = 0;
3390 ChangeEvent[x][y] = -1;
3392 ExplodePhase[x][y] = 0;
3393 ExplodeDelay[x][y] = 0;
3394 ExplodeField[x][y] = EX_TYPE_NONE;
3396 RunnerVisit[x][y] = 0;
3397 PlayerVisit[x][y] = 0;
3400 GfxRandom[x][y] = INIT_GFX_RANDOM();
3401 GfxElement[x][y] = EL_UNDEFINED;
3402 GfxAction[x][y] = ACTION_DEFAULT;
3403 GfxDir[x][y] = MV_NONE;
3404 GfxRedraw[x][y] = GFX_REDRAW_NONE;
3407 SCAN_PLAYFIELD(x, y)
3409 if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
3411 if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
3413 if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
3416 InitField(x, y, TRUE);
3418 ResetGfxAnimation(x, y);
3423 for (i = 0; i < MAX_PLAYERS; i++)
3425 struct PlayerInfo *player = &stored_player[i];
3427 /* set number of special actions for bored and sleeping animation */
3428 player->num_special_action_bored =
3429 get_num_special_action(player->artwork_element,
3430 ACTION_BORING_1, ACTION_BORING_LAST);
3431 player->num_special_action_sleeping =
3432 get_num_special_action(player->artwork_element,
3433 ACTION_SLEEPING_1, ACTION_SLEEPING_LAST);
3436 game.emulation = (emulate_bd ? EMU_BOULDERDASH :
3437 emulate_sb ? EMU_SOKOBAN :
3438 emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
3440 /* initialize type of slippery elements */
3441 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3443 if (!IS_CUSTOM_ELEMENT(i))
3445 /* default: elements slip down either to the left or right randomly */
3446 element_info[i].slippery_type = SLIPPERY_ANY_RANDOM;
3448 /* SP style elements prefer to slip down on the left side */
3449 if (game.engine_version >= VERSION_IDENT(3,1,1,0) && IS_SP_ELEMENT(i))
3450 element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT;
3452 /* BD style elements prefer to slip down on the left side */
3453 if (game.emulation == EMU_BOULDERDASH)
3454 element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT;
3458 /* initialize explosion and ignition delay */
3459 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3461 if (!IS_CUSTOM_ELEMENT(i))
3464 int delay = (((IS_SP_ELEMENT(i) && i != EL_EMPTY_SPACE) &&
3465 game.engine_version >= VERSION_IDENT(3,1,0,0)) ||
3466 game.emulation == EMU_SUPAPLEX ? 3 : 2);
3467 int last_phase = (num_phase + 1) * delay;
3468 int half_phase = (num_phase / 2) * delay;
3470 element_info[i].explosion_delay = last_phase - 1;
3471 element_info[i].ignition_delay = half_phase;
3473 if (i == EL_BLACK_ORB)
3474 element_info[i].ignition_delay = 1;
3478 /* correct non-moving belts to start moving left */
3479 for (i = 0; i < NUM_BELTS; i++)
3480 if (game.belt_dir[i] == MV_NONE)
3481 game.belt_dir_nr[i] = 3; /* not moving, next moving left */
3483 #if USE_NEW_PLAYER_ASSIGNMENTS
3484 /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */
3485 /* choose default local player */
3486 local_player = &stored_player[0];
3488 for (i = 0; i < MAX_PLAYERS; i++)
3489 stored_player[i].connected = FALSE;
3491 local_player->connected = TRUE;
3492 /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */
3496 for (i = 0; i < MAX_PLAYERS; i++)
3497 stored_player[i].connected = tape.player_participates[i];
3499 else if (game.team_mode && !options.network)
3501 /* try to guess locally connected team mode players (needed for correct
3502 assignment of player figures from level to locally playing players) */
3504 for (i = 0; i < MAX_PLAYERS; i++)
3505 if (setup.input[i].use_joystick ||
3506 setup.input[i].key.left != KSYM_UNDEFINED)
3507 stored_player[i].connected = TRUE;
3510 #if DEBUG_INIT_PLAYER
3513 printf("Player status after level initialization:\n");
3515 for (i = 0; i < MAX_PLAYERS; i++)
3517 struct PlayerInfo *player = &stored_player[i];
3519 printf("- player %d: present == %d, connected == %d, active == %d",
3525 if (local_player == player)
3526 printf(" (local player)");
3533 #if DEBUG_INIT_PLAYER
3535 printf("Reassigning players ...\n");
3538 /* check if any connected player was not found in playfield */
3539 for (i = 0; i < MAX_PLAYERS; i++)
3541 struct PlayerInfo *player = &stored_player[i];
3543 if (player->connected && !player->present)
3545 struct PlayerInfo *field_player = NULL;
3547 #if DEBUG_INIT_PLAYER
3549 printf("- looking for field player for player %d ...\n", i + 1);
3552 /* assign first free player found that is present in the playfield */
3554 /* first try: look for unmapped playfield player that is not connected */
3555 for (j = 0; j < MAX_PLAYERS; j++)
3556 if (field_player == NULL &&
3557 stored_player[j].present &&
3558 !stored_player[j].mapped &&
3559 !stored_player[j].connected)
3560 field_player = &stored_player[j];
3562 /* second try: look for *any* unmapped playfield player */
3563 for (j = 0; j < MAX_PLAYERS; j++)
3564 if (field_player == NULL &&
3565 stored_player[j].present &&
3566 !stored_player[j].mapped)
3567 field_player = &stored_player[j];
3569 if (field_player != NULL)
3571 int jx = field_player->jx, jy = field_player->jy;
3573 #if DEBUG_INIT_PLAYER
3575 printf("- found player %d\n", field_player->index_nr + 1);
3578 player->present = FALSE;
3579 player->active = FALSE;
3581 field_player->present = TRUE;
3582 field_player->active = TRUE;
3585 player->initial_element = field_player->initial_element;
3586 player->artwork_element = field_player->artwork_element;
3588 player->block_last_field = field_player->block_last_field;
3589 player->block_delay_adjustment = field_player->block_delay_adjustment;
3592 StorePlayer[jx][jy] = field_player->element_nr;
3594 field_player->jx = field_player->last_jx = jx;
3595 field_player->jy = field_player->last_jy = jy;
3597 if (local_player == player)
3598 local_player = field_player;
3600 map_player_action[field_player->index_nr] = i;
3602 field_player->mapped = TRUE;
3604 #if DEBUG_INIT_PLAYER
3606 printf("- map_player_action[%d] == %d\n",
3607 field_player->index_nr + 1, i + 1);
3612 if (player->connected && player->present)
3613 player->mapped = TRUE;
3616 #if DEBUG_INIT_PLAYER
3619 printf("Player status after player assignment (first stage):\n");
3621 for (i = 0; i < MAX_PLAYERS; i++)
3623 struct PlayerInfo *player = &stored_player[i];
3625 printf("- player %d: present == %d, connected == %d, active == %d",
3631 if (local_player == player)
3632 printf(" (local player)");
3641 /* check if any connected player was not found in playfield */
3642 for (i = 0; i < MAX_PLAYERS; i++)
3644 struct PlayerInfo *player = &stored_player[i];
3646 if (player->connected && !player->present)
3648 for (j = 0; j < MAX_PLAYERS; j++)
3650 struct PlayerInfo *field_player = &stored_player[j];
3651 int jx = field_player->jx, jy = field_player->jy;
3653 /* assign first free player found that is present in the playfield */
3654 if (field_player->present && !field_player->connected)
3656 player->present = TRUE;
3657 player->active = TRUE;
3659 field_player->present = FALSE;
3660 field_player->active = FALSE;
3662 player->initial_element = field_player->initial_element;
3663 player->artwork_element = field_player->artwork_element;
3665 player->block_last_field = field_player->block_last_field;
3666 player->block_delay_adjustment = field_player->block_delay_adjustment;
3668 StorePlayer[jx][jy] = player->element_nr;
3670 player->jx = player->last_jx = jx;
3671 player->jy = player->last_jy = jy;
3681 printf("::: local_player->present == %d\n", local_player->present);
3686 /* when playing a tape, eliminate all players who do not participate */
3688 #if USE_NEW_PLAYER_ASSIGNMENTS
3690 if (!game.team_mode)
3692 for (i = 0; i < MAX_PLAYERS; i++)
3694 if (stored_player[i].active &&
3695 !tape.player_participates[map_player_action[i]])
3697 struct PlayerInfo *player = &stored_player[i];
3698 int jx = player->jx, jy = player->jy;
3700 #if DEBUG_INIT_PLAYER
3702 printf("Removing player %d at (%d, %d)\n", i + 1, jx, jy);
3705 player->active = FALSE;
3706 StorePlayer[jx][jy] = 0;
3707 Feld[jx][jy] = EL_EMPTY;
3714 for (i = 0; i < MAX_PLAYERS; i++)
3716 if (stored_player[i].active &&
3717 !tape.player_participates[i])
3719 struct PlayerInfo *player = &stored_player[i];
3720 int jx = player->jx, jy = player->jy;
3722 player->active = FALSE;
3723 StorePlayer[jx][jy] = 0;
3724 Feld[jx][jy] = EL_EMPTY;
3729 else if (!options.network && !game.team_mode) /* && !tape.playing */
3731 /* when in single player mode, eliminate all but the first active player */
3733 for (i = 0; i < MAX_PLAYERS; i++)
3735 if (stored_player[i].active)
3737 for (j = i + 1; j < MAX_PLAYERS; j++)
3739 if (stored_player[j].active)
3741 struct PlayerInfo *player = &stored_player[j];
3742 int jx = player->jx, jy = player->jy;
3744 player->active = FALSE;
3745 player->present = FALSE;
3747 StorePlayer[jx][jy] = 0;
3748 Feld[jx][jy] = EL_EMPTY;
3755 /* when recording the game, store which players take part in the game */
3758 #if USE_NEW_PLAYER_ASSIGNMENTS
3759 for (i = 0; i < MAX_PLAYERS; i++)
3760 if (stored_player[i].connected)
3761 tape.player_participates[i] = TRUE;
3763 for (i = 0; i < MAX_PLAYERS; i++)
3764 if (stored_player[i].active)
3765 tape.player_participates[i] = TRUE;
3769 #if DEBUG_INIT_PLAYER
3772 printf("Player status after player assignment (final stage):\n");
3774 for (i = 0; i < MAX_PLAYERS; i++)
3776 struct PlayerInfo *player = &stored_player[i];
3778 printf("- player %d: present == %d, connected == %d, active == %d",
3784 if (local_player == player)
3785 printf(" (local player)");
3792 if (BorderElement == EL_EMPTY)
3795 SBX_Right = lev_fieldx - SCR_FIELDX;
3797 SBY_Lower = lev_fieldy - SCR_FIELDY;
3802 SBX_Right = lev_fieldx - SCR_FIELDX + 1;
3804 SBY_Lower = lev_fieldy - SCR_FIELDY + 1;
3807 if (full_lev_fieldx <= SCR_FIELDX)
3808 SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2;
3809 if (full_lev_fieldy <= SCR_FIELDY)
3810 SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2;
3812 if (EVEN(SCR_FIELDX) && full_lev_fieldx > SCR_FIELDX)
3814 if (EVEN(SCR_FIELDY) && full_lev_fieldy > SCR_FIELDY)
3817 /* if local player not found, look for custom element that might create
3818 the player (make some assumptions about the right custom element) */
3819 if (!local_player->present)
3821 int start_x = 0, start_y = 0;
3822 int found_rating = 0;
3823 int found_element = EL_UNDEFINED;
3824 int player_nr = local_player->index_nr;
3826 SCAN_PLAYFIELD(x, y)
3828 int element = Feld[x][y];
3833 if (level.use_start_element[player_nr] &&
3834 level.start_element[player_nr] == element &&
3841 found_element = element;
3844 if (!IS_CUSTOM_ELEMENT(element))
3847 if (CAN_CHANGE(element))
3849 for (i = 0; i < element_info[element].num_change_pages; i++)
3851 /* check for player created from custom element as single target */
3852 content = element_info[element].change_page[i].target_element;
3853 is_player = ELEM_IS_PLAYER(content);
3855 if (is_player && (found_rating < 3 ||
3856 (found_rating == 3 && element < found_element)))
3862 found_element = element;
3867 for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3; xx++)
3869 /* check for player created from custom element as explosion content */
3870 content = element_info[element].content.e[xx][yy];
3871 is_player = ELEM_IS_PLAYER(content);
3873 if (is_player && (found_rating < 2 ||
3874 (found_rating == 2 && element < found_element)))
3876 start_x = x + xx - 1;
3877 start_y = y + yy - 1;
3880 found_element = element;
3883 if (!CAN_CHANGE(element))
3886 for (i = 0; i < element_info[element].num_change_pages; i++)
3888 /* check for player created from custom element as extended target */
3890 element_info[element].change_page[i].target_content.e[xx][yy];
3892 is_player = ELEM_IS_PLAYER(content);
3894 if (is_player && (found_rating < 1 ||
3895 (found_rating == 1 && element < found_element)))
3897 start_x = x + xx - 1;
3898 start_y = y + yy - 1;
3901 found_element = element;
3907 scroll_x = SCROLL_POSITION_X(start_x);
3908 scroll_y = SCROLL_POSITION_Y(start_y);
3912 scroll_x = SCROLL_POSITION_X(local_player->jx);
3913 scroll_y = SCROLL_POSITION_Y(local_player->jy);
3916 /* !!! FIX THIS (START) !!! */
3917 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3919 InitGameEngine_EM();
3921 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3923 InitGameEngine_SP();
3927 DrawLevel(REDRAW_FIELD);
3930 /* after drawing the level, correct some elements */
3931 if (game.timegate_time_left == 0)
3932 CloseAllOpenTimegates();
3935 /* blit playfield from scroll buffer to normal back buffer for fading in */
3936 BlitScreenToBitmap(backbuffer);
3937 /* !!! FIX THIS (END) !!! */
3939 DrawMaskedBorder(fade_mask);
3944 // full screen redraw is required at this point in the following cases:
3945 // - special editor door undrawn when game was started from level editor
3946 // - drawing area (playfield) was changed and has to be removed completely
3947 redraw_mask = REDRAW_ALL;
3951 if (!game.restart_level)
3953 /* copy default game door content to main double buffer */
3955 /* !!! CHECK AGAIN !!! */
3956 SetPanelBackground();
3957 // SetDoorBackgroundImage(IMG_BACKGROUND_PANEL);
3958 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3961 SetPanelBackground();
3962 SetDrawBackgroundMask(REDRAW_DOOR_1);
3964 UpdateAndDisplayGameControlValues();
3966 if (!game.restart_level)
3972 CreateGameButtons();
3974 game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
3975 game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
3976 game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
3981 /* copy actual game door content to door double buffer for OpenDoor() */
3982 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3984 OpenDoor(DOOR_OPEN_ALL);
3986 PlaySound(SND_GAME_STARTING);
3988 if (setup.sound_music)
3991 KeyboardAutoRepeatOffUnlessAutoplay();
3993 #if DEBUG_INIT_PLAYER
3996 printf("Player status (final):\n");
3998 for (i = 0; i < MAX_PLAYERS; i++)
4000 struct PlayerInfo *player = &stored_player[i];
4002 printf("- player %d: present == %d, connected == %d, active == %d",
4008 if (local_player == player)
4009 printf(" (local player)");
4022 if (!game.restart_level && !tape.playing)
4024 LevelStats_incPlayed(level_nr);
4026 SaveLevelSetup_SeriesInfo();
4029 game.restart_level = FALSE;
4031 SaveEngineSnapshotToListInitial();
4034 void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y,
4035 int actual_player_x, int actual_player_y)
4037 /* this is used for non-R'n'D game engines to update certain engine values */
4039 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4041 actual_player_x = correctLevelPosX_EM(actual_player_x);
4042 actual_player_y = correctLevelPosY_EM(actual_player_y);
4045 /* needed to determine if sounds are played within the visible screen area */
4046 scroll_x = actual_scroll_x;
4047 scroll_y = actual_scroll_y;
4049 /* needed to get player position for "follow finger" playing input method */
4050 local_player->jx = actual_player_x;
4051 local_player->jy = actual_player_y;
4054 void InitMovDir(int x, int y)
4056 int i, element = Feld[x][y];
4057 static int xy[4][2] =
4064 static int direction[3][4] =
4066 { MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN },
4067 { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP },
4068 { MV_LEFT, MV_RIGHT, MV_UP, MV_DOWN }
4077 Feld[x][y] = EL_BUG;
4078 MovDir[x][y] = direction[0][element - EL_BUG_RIGHT];
4081 case EL_SPACESHIP_RIGHT:
4082 case EL_SPACESHIP_UP:
4083 case EL_SPACESHIP_LEFT:
4084 case EL_SPACESHIP_DOWN:
4085 Feld[x][y] = EL_SPACESHIP;
4086 MovDir[x][y] = direction[0][element - EL_SPACESHIP_RIGHT];
4089 case EL_BD_BUTTERFLY_RIGHT:
4090 case EL_BD_BUTTERFLY_UP:
4091 case EL_BD_BUTTERFLY_LEFT:
4092 case EL_BD_BUTTERFLY_DOWN:
4093 Feld[x][y] = EL_BD_BUTTERFLY;
4094 MovDir[x][y] = direction[0][element - EL_BD_BUTTERFLY_RIGHT];
4097 case EL_BD_FIREFLY_RIGHT:
4098 case EL_BD_FIREFLY_UP:
4099 case EL_BD_FIREFLY_LEFT:
4100 case EL_BD_FIREFLY_DOWN:
4101 Feld[x][y] = EL_BD_FIREFLY;
4102 MovDir[x][y] = direction[0][element - EL_BD_FIREFLY_RIGHT];
4105 case EL_PACMAN_RIGHT:
4107 case EL_PACMAN_LEFT:
4108 case EL_PACMAN_DOWN:
4109 Feld[x][y] = EL_PACMAN;
4110 MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT];
4113 case EL_YAMYAM_LEFT:
4114 case EL_YAMYAM_RIGHT:
4116 case EL_YAMYAM_DOWN:
4117 Feld[x][y] = EL_YAMYAM;
4118 MovDir[x][y] = direction[2][element - EL_YAMYAM_LEFT];
4121 case EL_SP_SNIKSNAK:
4122 MovDir[x][y] = MV_UP;
4125 case EL_SP_ELECTRON:
4126 MovDir[x][y] = MV_LEFT;
4133 Feld[x][y] = EL_MOLE;
4134 MovDir[x][y] = direction[2][element - EL_MOLE_LEFT];
4138 if (IS_CUSTOM_ELEMENT(element))
4140 struct ElementInfo *ei = &element_info[element];
4141 int move_direction_initial = ei->move_direction_initial;
4142 int move_pattern = ei->move_pattern;
4144 if (move_direction_initial == MV_START_PREVIOUS)
4146 if (MovDir[x][y] != MV_NONE)
4149 move_direction_initial = MV_START_AUTOMATIC;
4152 if (move_direction_initial == MV_START_RANDOM)
4153 MovDir[x][y] = 1 << RND(4);
4154 else if (move_direction_initial & MV_ANY_DIRECTION)
4155 MovDir[x][y] = move_direction_initial;
4156 else if (move_pattern == MV_ALL_DIRECTIONS ||
4157 move_pattern == MV_TURNING_LEFT ||
4158 move_pattern == MV_TURNING_RIGHT ||
4159 move_pattern == MV_TURNING_LEFT_RIGHT ||
4160 move_pattern == MV_TURNING_RIGHT_LEFT ||
4161 move_pattern == MV_TURNING_RANDOM)
4162 MovDir[x][y] = 1 << RND(4);
4163 else if (move_pattern == MV_HORIZONTAL)
4164 MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT);
4165 else if (move_pattern == MV_VERTICAL)
4166 MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN);
4167 else if (move_pattern & MV_ANY_DIRECTION)
4168 MovDir[x][y] = element_info[element].move_pattern;
4169 else if (move_pattern == MV_ALONG_LEFT_SIDE ||
4170 move_pattern == MV_ALONG_RIGHT_SIDE)
4172 /* use random direction as default start direction */
4173 if (game.engine_version >= VERSION_IDENT(3,1,0,0))
4174 MovDir[x][y] = 1 << RND(4);
4176 for (i = 0; i < NUM_DIRECTIONS; i++)
4178 int x1 = x + xy[i][0];
4179 int y1 = y + xy[i][1];
4181 if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
4183 if (move_pattern == MV_ALONG_RIGHT_SIDE)
4184 MovDir[x][y] = direction[0][i];
4186 MovDir[x][y] = direction[1][i];
4195 MovDir[x][y] = 1 << RND(4);
4197 if (element != EL_BUG &&
4198 element != EL_SPACESHIP &&
4199 element != EL_BD_BUTTERFLY &&
4200 element != EL_BD_FIREFLY)
4203 for (i = 0; i < NUM_DIRECTIONS; i++)
4205 int x1 = x + xy[i][0];
4206 int y1 = y + xy[i][1];
4208 if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
4210 if (element == EL_BUG || element == EL_BD_BUTTERFLY)
4212 MovDir[x][y] = direction[0][i];
4215 else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY ||
4216 element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
4218 MovDir[x][y] = direction[1][i];
4227 GfxDir[x][y] = MovDir[x][y];
4230 void InitAmoebaNr(int x, int y)
4233 int group_nr = AmoebeNachbarNr(x, y);
4237 for (i = 1; i < MAX_NUM_AMOEBA; i++)
4239 if (AmoebaCnt[i] == 0)
4247 AmoebaNr[x][y] = group_nr;
4248 AmoebaCnt[group_nr]++;
4249 AmoebaCnt2[group_nr]++;
4252 static void PlayerWins(struct PlayerInfo *player)
4254 player->LevelSolved = TRUE;
4255 player->GameOver = TRUE;
4257 player->score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
4258 level.native_em_level->lev->score : player->score);
4260 player->LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed :
4262 player->LevelSolved_CountingScore = player->score_final;
4267 static int time, time_final;
4268 static int score, score_final;
4269 static int game_over_delay_1 = 0;
4270 static int game_over_delay_2 = 0;
4271 int game_over_delay_value_1 = 50;
4272 int game_over_delay_value_2 = 50;
4274 if (!local_player->LevelSolved_GameWon)
4278 /* do not start end game actions before the player stops moving (to exit) */
4279 if (local_player->MovPos)
4282 local_player->LevelSolved_GameWon = TRUE;
4283 local_player->LevelSolved_SaveTape = tape.recording;
4284 local_player->LevelSolved_SaveScore = !tape.playing;
4288 LevelStats_incSolved(level_nr);
4290 SaveLevelSetup_SeriesInfo();
4293 if (tape.auto_play) /* tape might already be stopped here */
4294 tape.auto_play_level_solved = TRUE;
4298 game_over_delay_1 = game_over_delay_value_1;
4299 game_over_delay_2 = game_over_delay_value_2;
4301 time = time_final = (game.no_time_limit ? TimePlayed : TimeLeft);
4302 score = score_final = local_player->score_final;
4307 score_final += TimeLeft * level.score[SC_TIME_BONUS];
4309 else if (game.no_time_limit && TimePlayed < 999)
4312 score_final += (999 - TimePlayed) * level.score[SC_TIME_BONUS];
4315 local_player->score_final = score_final;
4317 if (level_editor_test_game)
4320 score = score_final;
4322 local_player->LevelSolved_CountingTime = time;
4323 local_player->LevelSolved_CountingScore = score;
4325 game_panel_controls[GAME_PANEL_TIME].value = time;
4326 game_panel_controls[GAME_PANEL_SCORE].value = score;
4328 DisplayGameControlValues();
4331 if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
4333 if (ExitX >= 0 && ExitY >= 0) /* local player has left the level */
4335 /* close exit door after last player */
4336 if ((AllPlayersGone &&
4337 (Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
4338 Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN ||
4339 Feld[ExitX][ExitY] == EL_STEEL_EXIT_OPEN)) ||
4340 Feld[ExitX][ExitY] == EL_EM_EXIT_OPEN ||
4341 Feld[ExitX][ExitY] == EL_EM_STEEL_EXIT_OPEN)
4343 int element = Feld[ExitX][ExitY];
4345 Feld[ExitX][ExitY] =
4346 (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING :
4347 element == EL_EM_EXIT_OPEN ? EL_EM_EXIT_CLOSING :
4348 element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING:
4349 element == EL_STEEL_EXIT_OPEN ? EL_STEEL_EXIT_CLOSING:
4350 EL_EM_STEEL_EXIT_CLOSING);
4352 PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING);
4355 /* player disappears */
4356 DrawLevelField(ExitX, ExitY);
4359 for (i = 0; i < MAX_PLAYERS; i++)
4361 struct PlayerInfo *player = &stored_player[i];
4363 if (player->present)
4365 RemovePlayer(player);
4367 /* player disappears */
4368 DrawLevelField(player->jx, player->jy);
4373 PlaySound(SND_GAME_WINNING);
4376 if (game_over_delay_1 > 0)
4378 game_over_delay_1--;
4383 if (time != time_final)
4385 int time_to_go = ABS(time_final - time);
4386 int time_count_dir = (time < time_final ? +1 : -1);
4387 int time_count_steps = (time_to_go > 100 && time_to_go % 10 == 0 ? 10 : 1);
4389 time += time_count_steps * time_count_dir;
4390 score += time_count_steps * level.score[SC_TIME_BONUS];
4392 local_player->LevelSolved_CountingTime = time;
4393 local_player->LevelSolved_CountingScore = score;
4395 game_panel_controls[GAME_PANEL_TIME].value = time;
4396 game_panel_controls[GAME_PANEL_SCORE].value = score;
4398 DisplayGameControlValues();
4400 if (time == time_final)
4401 StopSound(SND_GAME_LEVELTIME_BONUS);
4402 else if (setup.sound_loops)
4403 PlaySoundLoop(SND_GAME_LEVELTIME_BONUS);
4405 PlaySound(SND_GAME_LEVELTIME_BONUS);
4410 local_player->LevelSolved_PanelOff = TRUE;
4412 if (game_over_delay_2 > 0)
4414 game_over_delay_2--;
4425 boolean raise_level = FALSE;
4427 local_player->LevelSolved_GameEnd = TRUE;
4429 if (!global.use_envelope_request)
4430 CloseDoor(DOOR_CLOSE_1);
4432 if (local_player->LevelSolved_SaveTape)
4434 SaveTapeChecked(tape.level_nr); /* ask to save tape */
4437 CloseDoor(DOOR_CLOSE_ALL);
4439 if (level_editor_test_game)
4441 SetGameStatus(GAME_MODE_MAIN);
4448 if (!local_player->LevelSolved_SaveScore)
4450 SetGameStatus(GAME_MODE_MAIN);
4457 if (level_nr == leveldir_current->handicap_level)
4459 leveldir_current->handicap_level++;
4461 SaveLevelSetup_SeriesInfo();
4464 if (level_nr < leveldir_current->last_level)
4465 raise_level = TRUE; /* advance to next level */
4467 if ((hi_pos = NewHiScore()) >= 0)
4469 SetGameStatus(GAME_MODE_SCORES);
4471 DrawHallOfFame(hi_pos);
4481 SetGameStatus(GAME_MODE_MAIN);
4498 LoadScore(level_nr);
4500 if (strEqual(setup.player_name, EMPTY_PLAYER_NAME) ||
4501 local_player->score_final < highscore[MAX_SCORE_ENTRIES - 1].Score)
4504 for (k = 0; k < MAX_SCORE_ENTRIES; k++)
4506 if (local_player->score_final > highscore[k].Score)
4508 /* player has made it to the hall of fame */
4510 if (k < MAX_SCORE_ENTRIES - 1)
4512 int m = MAX_SCORE_ENTRIES - 1;
4515 for (l = k; l < MAX_SCORE_ENTRIES; l++)
4516 if (strEqual(setup.player_name, highscore[l].Name))
4518 if (m == k) /* player's new highscore overwrites his old one */
4522 for (l = m; l > k; l--)
4524 strcpy(highscore[l].Name, highscore[l - 1].Name);
4525 highscore[l].Score = highscore[l - 1].Score;
4532 strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN);
4533 highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0';
4534 highscore[k].Score = local_player->score_final;
4540 else if (!strncmp(setup.player_name, highscore[k].Name,
4541 MAX_PLAYER_NAME_LEN))
4542 break; /* player already there with a higher score */
4548 SaveScore(level_nr);
4553 inline static int getElementMoveStepsizeExt(int x, int y, int direction)
4555 int element = Feld[x][y];
4556 int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
4557 int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
4558 int horiz_move = (dx != 0);
4559 int sign = (horiz_move ? dx : dy);
4560 int step = sign * element_info[element].move_stepsize;
4562 /* special values for move stepsize for spring and things on conveyor belt */
4565 if (CAN_FALL(element) &&
4566 y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
4567 step = sign * MOVE_STEPSIZE_NORMAL / 2;
4568 else if (element == EL_SPRING)
4569 step = sign * MOVE_STEPSIZE_NORMAL * 2;
4575 inline static int getElementMoveStepsize(int x, int y)
4577 return getElementMoveStepsizeExt(x, y, MovDir[x][y]);
4580 void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir)
4582 if (player->GfxAction != action || player->GfxDir != dir)
4584 player->GfxAction = action;
4585 player->GfxDir = dir;
4587 player->StepFrame = 0;
4591 static void ResetGfxFrame(int x, int y)
4593 int element = Feld[x][y];
4594 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
4596 if (graphic_info[graphic].anim_global_sync)
4597 GfxFrame[x][y] = FrameCounter;
4598 else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
4599 GfxFrame[x][y] = CustomValue[x][y];
4600 else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
4601 GfxFrame[x][y] = element_info[element].collect_score;
4602 else if (ANIM_MODE(graphic) == ANIM_CE_DELAY)
4603 GfxFrame[x][y] = ChangeDelay[x][y];
4606 static void ResetGfxAnimation(int x, int y)
4608 GfxAction[x][y] = ACTION_DEFAULT;
4609 GfxDir[x][y] = MovDir[x][y];
4612 ResetGfxFrame(x, y);
4615 static void ResetRandomAnimationValue(int x, int y)
4617 GfxRandom[x][y] = INIT_GFX_RANDOM();
4620 void InitMovingField(int x, int y, int direction)
4622 int element = Feld[x][y];
4623 int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
4624 int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
4627 boolean is_moving_before, is_moving_after;
4629 /* check if element was/is moving or being moved before/after mode change */
4630 is_moving_before = (WasJustMoving[x][y] != 0);
4631 is_moving_after = (getElementMoveStepsizeExt(x, y, direction) != 0);
4633 /* reset animation only for moving elements which change direction of moving
4634 or which just started or stopped moving
4635 (else CEs with property "can move" / "not moving" are reset each frame) */
4636 if (is_moving_before != is_moving_after ||
4637 direction != MovDir[x][y])
4638 ResetGfxAnimation(x, y);
4640 MovDir[x][y] = direction;
4641 GfxDir[x][y] = direction;
4643 GfxAction[x][y] = (!is_moving_after ? ACTION_WAITING :
4644 direction == MV_DOWN && CAN_FALL(element) ?
4645 ACTION_FALLING : ACTION_MOVING);
4647 /* this is needed for CEs with property "can move" / "not moving" */
4649 if (is_moving_after)
4651 if (Feld[newx][newy] == EL_EMPTY)
4652 Feld[newx][newy] = EL_BLOCKED;
4654 MovDir[newx][newy] = MovDir[x][y];
4656 CustomValue[newx][newy] = CustomValue[x][y];
4658 GfxFrame[newx][newy] = GfxFrame[x][y];
4659 GfxRandom[newx][newy] = GfxRandom[x][y];
4660 GfxAction[newx][newy] = GfxAction[x][y];
4661 GfxDir[newx][newy] = GfxDir[x][y];
4665 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
4667 int direction = MovDir[x][y];
4668 int newx = x + (direction & MV_LEFT ? -1 : direction & MV_RIGHT ? +1 : 0);
4669 int newy = y + (direction & MV_UP ? -1 : direction & MV_DOWN ? +1 : 0);