File: | src/takeover.c |
Location: | line 743, column 5 |
Description: | Value stored to 'row' is never read |
1 | /* |
2 | * |
3 | * Copyright (c) 2004-2010 Arthur Huillet |
4 | * Copyright (c) 1994, 2002, 2003 Johannes Prix |
5 | * Copyright (c) 1994, 2002 Reinhard Prix |
6 | * |
7 | * |
8 | * This file is part of Freedroid |
9 | * |
10 | * Freedroid is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. |
14 | * |
15 | * Freedroid is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. |
19 | * |
20 | * You should have received a copy of the GNU General Public License |
21 | * along with Freedroid; see the file COPYING. If not, write to the |
22 | * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
23 | * MA 02111-1307 USA |
24 | * |
25 | */ |
26 | /** |
27 | * This file does everything that has to do with the takeover game from |
28 | * the original paradroid game. |
29 | */ |
30 | |
31 | #define _takeover_c |
32 | |
33 | #include "system.h" |
34 | |
35 | #include "defs.h" |
36 | #include "struct.h" |
37 | #include "global.h" |
38 | #include "proto.h" |
39 | #include "takeover.h" |
40 | #include "map.h" |
41 | #include "widgets/widgets.h" |
42 | |
43 | Uint32 cur_time; // current time in ms |
44 | |
45 | // Takeover images |
46 | static struct image FillBlocks[NUM_FILL_BLOCKS3]; |
47 | static struct image CapsuleBlocks[NUM_CAPS_BLOCKS3]; |
48 | static struct image ToGameBlocks[NUM_TO_BLOCKS2*5*11]; |
49 | static struct image ToGroundBlocks[NUM_GROUND_BLOCKS6]; |
50 | static struct image ToColumnBlock; |
51 | static struct image ToLeaderBlock; |
52 | |
53 | //-------------------- |
54 | // Class seperation of the blocks |
55 | // |
56 | int BlockClass[TO_BLOCKS11] = { |
57 | CONNECTOR0, // cable |
58 | NON_CONNECTOR1, // end of cable |
59 | CONNECTOR0, // re-enforcer |
60 | CONNECTOR0, // color-change |
61 | CONNECTOR0, // bridge above |
62 | NON_CONNECTOR1, // bridge middle |
63 | CONNECTOR0, // bridge below |
64 | NON_CONNECTOR1, // uniter above |
65 | CONNECTOR0, // uniter middle |
66 | NON_CONNECTOR1, // uniter below |
67 | NON_CONNECTOR1 // empty |
68 | }; |
69 | |
70 | //-------------------- |
71 | // Probability of the various elements |
72 | // |
73 | #define MAX_PROB100 100 |
74 | int ElementProb[TO_ELEMENTS6] = { |
75 | 100, // EL_CABLE |
76 | 2, // EL_CABLE_END |
77 | 5, // EL_AMPLIFIER |
78 | 5, // EL_COLOR_EXCHANGER: only on last layer |
79 | 5, // EL_SEPARATOR |
80 | 5 // EL_GATE |
81 | }; |
82 | |
83 | int max_opponent_capsules; |
84 | int NumCapsules[TO_COLORS2] = { |
85 | 0, 0 |
86 | }; |
87 | |
88 | point LeftCapsulesStart[TO_COLORS2] = { |
89 | {YELLOW_LEFT_CAPSULES_X4, YELLOW_LEFT_CAPSULES_Y2*27}, |
90 | {PURPLE_LEFT_CAPSULES_X2*255 + 2*30 -10, PURPLE_LEFT_CAPSULES_Y2*27} |
91 | }; |
92 | |
93 | point CurCapsuleStart[TO_COLORS2] = { |
94 | {YELLOW_CUR_CAPSULE_X2*26, YELLOW_CUR_CAPSULE_Y2*19}, |
95 | {PURPLE_CUR_CAPSULE_X2*255, PURPLE_CUR_CAPSULE_Y2*19} |
96 | }; |
97 | |
98 | point PlaygroundStart[TO_COLORS2] = { |
99 | {YELLOW_PLAYGROUND_X2*33, YELLOW_PLAYGROUND_Y2*26}, |
100 | {PURPLE_PLAYGROUND_X2*159, PURPLE_PLAYGROUND_Y2*26} |
101 | }; |
102 | |
103 | point DroidStart[TO_COLORS2] = { |
104 | {YELLOW_DROID_X2*40, YELLOW_DROID_Y0}, |
105 | {PURPLE_DROID_X2*220, PURPLE_DROID_Y0} |
106 | }; |
107 | |
108 | int CapsuleCurRow[TO_COLORS2] = { 0, 0 }; |
109 | |
110 | int LeaderColor = YELLOW; /* momentary leading color */ |
111 | int LeaderCapsuleCount = 6; /* capsule count of currently leading color */ |
112 | int YourColor = YELLOW; |
113 | int OpponentColor = PURPLE; |
114 | int OpponentType; /* The droid-type of your opponent */ |
115 | enemy *cdroid; |
116 | |
117 | /* the display column */ |
118 | int DisplayColumn[NUM_LINES12] = { |
119 | YELLOW, PURPLE, YELLOW, PURPLE, YELLOW, PURPLE, YELLOW, PURPLE, YELLOW, PURPLE, |
120 | YELLOW, PURPLE |
121 | }; |
122 | |
123 | SDL_Color to_bg_color = { 199, 199, 199 }; |
124 | |
125 | playground_t ToPlayground; |
126 | playground_t ActivationMap; |
127 | playground_t CapsuleCountdown; |
128 | |
129 | void EvaluatePlayground(void); |
130 | float EvaluatePosition(const int color, const int row, const int layer, const int endgame); |
131 | float EvaluateCenterPosition(const int color, const int row, const int layer, const int endgame); |
132 | void AdvancedEnemyTakeoverMovements(const int countdown); |
133 | |
134 | static void ShowPlayground(enemy *target); |
135 | |
136 | static void display_takeover_help() |
137 | { |
138 | PlayATitleFile("TakeoverInstructions.lua"); |
139 | } |
140 | |
141 | /** |
142 | * Display the picture of a droid |
143 | */ |
144 | static void show_droid_picture(int PosX, int PosY, int type) |
145 | { |
146 | char filename[5000]; |
147 | static char LastImageSeriesPrefix[1000] = "NONE_AT_ALL"; |
148 | #define NUMBER_OF_IMAGES_IN_DROID_PORTRAIT_ROTATION32 32 |
149 | static struct image droid_images[NUMBER_OF_IMAGES_IN_DROID_PORTRAIT_ROTATION32]; |
150 | int RotationIndex; |
151 | |
152 | if (!strcmp(Droidmap[type].droid_portrait_rotation_series_prefix, "NONE_AVAILABLE_YET")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (Droidmap[type].droid_portrait_rotation_series_prefix) && __builtin_constant_p ("NONE_AVAILABLE_YET") && (__s1_len = strlen (Droidmap[type].droid_portrait_rotation_series_prefix ), __s2_len = strlen ("NONE_AVAILABLE_YET"), (!((size_t)(const void *)((Droidmap[type].droid_portrait_rotation_series_prefix ) + 1) - (size_t)(const void *)(Droidmap[type].droid_portrait_rotation_series_prefix ) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("NONE_AVAILABLE_YET") + 1) - (size_t)(const void *)("NONE_AVAILABLE_YET" ) == 1) || __s2_len >= 4)) ? __builtin_strcmp (Droidmap[type ].droid_portrait_rotation_series_prefix, "NONE_AVAILABLE_YET" ) : (__builtin_constant_p (Droidmap[type].droid_portrait_rotation_series_prefix ) && ((size_t)(const void *)((Droidmap[type].droid_portrait_rotation_series_prefix ) + 1) - (size_t)(const void *)(Droidmap[type].droid_portrait_rotation_series_prefix ) == 1) && (__s1_len = strlen (Droidmap[type].droid_portrait_rotation_series_prefix ), __s1_len < 4) ? (__builtin_constant_p ("NONE_AVAILABLE_YET" ) && ((size_t)(const void *)(("NONE_AVAILABLE_YET") + 1) - (size_t)(const void *)("NONE_AVAILABLE_YET") == 1) ? __builtin_strcmp (Droidmap[type].droid_portrait_rotation_series_prefix, "NONE_AVAILABLE_YET" ) : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("NONE_AVAILABLE_YET"); int __result = (((const unsigned char *) (const char *) (Droidmap[type].droid_portrait_rotation_series_prefix ))[0] - __s2[0]); if (__s1_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (Droidmap [type].droid_portrait_rotation_series_prefix))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = ( ((const unsigned char *) (const char *) (Droidmap[type].droid_portrait_rotation_series_prefix ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (Droidmap [type].droid_portrait_rotation_series_prefix))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("NONE_AVAILABLE_YET" ) && ((size_t)(const void *)(("NONE_AVAILABLE_YET") + 1) - (size_t)(const void *)("NONE_AVAILABLE_YET") == 1) && (__s2_len = strlen ("NONE_AVAILABLE_YET"), __s2_len < 4) ? (__builtin_constant_p (Droidmap[type].droid_portrait_rotation_series_prefix ) && ((size_t)(const void *)((Droidmap[type].droid_portrait_rotation_series_prefix ) + 1) - (size_t)(const void *)(Droidmap[type].droid_portrait_rotation_series_prefix ) == 1) ? __builtin_strcmp (Droidmap[type].droid_portrait_rotation_series_prefix , "NONE_AVAILABLE_YET") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (Droidmap [type].droid_portrait_rotation_series_prefix); int __result = (((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (Droidmap [type].droid_portrait_rotation_series_prefix, "NONE_AVAILABLE_YET" )))); })) |
153 | return; |
154 | |
155 | // Maybe we have to reload the whole image series |
156 | // |
157 | if (strcmp(LastImageSeriesPrefix, Droidmap[type].droid_portrait_rotation_series_prefix)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (LastImageSeriesPrefix) && __builtin_constant_p (Droidmap [type].droid_portrait_rotation_series_prefix) && (__s1_len = strlen (LastImageSeriesPrefix), __s2_len = strlen (Droidmap [type].droid_portrait_rotation_series_prefix), (!((size_t)(const void *)((LastImageSeriesPrefix) + 1) - (size_t)(const void * )(LastImageSeriesPrefix) == 1) || __s1_len >= 4) && (!((size_t)(const void *)((Droidmap[type].droid_portrait_rotation_series_prefix ) + 1) - (size_t)(const void *)(Droidmap[type].droid_portrait_rotation_series_prefix ) == 1) || __s2_len >= 4)) ? __builtin_strcmp (LastImageSeriesPrefix , Droidmap[type].droid_portrait_rotation_series_prefix) : (__builtin_constant_p (LastImageSeriesPrefix) && ((size_t)(const void *)(( LastImageSeriesPrefix) + 1) - (size_t)(const void *)(LastImageSeriesPrefix ) == 1) && (__s1_len = strlen (LastImageSeriesPrefix) , __s1_len < 4) ? (__builtin_constant_p (Droidmap[type].droid_portrait_rotation_series_prefix ) && ((size_t)(const void *)((Droidmap[type].droid_portrait_rotation_series_prefix ) + 1) - (size_t)(const void *)(Droidmap[type].droid_portrait_rotation_series_prefix ) == 1) ? __builtin_strcmp (LastImageSeriesPrefix, Droidmap[type ].droid_portrait_rotation_series_prefix) : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (Droidmap[type].droid_portrait_rotation_series_prefix); int __result = (((const unsigned char *) (const char *) (LastImageSeriesPrefix ))[0] - __s2[0]); if (__s1_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (LastImageSeriesPrefix ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (LastImageSeriesPrefix ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (LastImageSeriesPrefix ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( Droidmap[type].droid_portrait_rotation_series_prefix) && ((size_t)(const void *)((Droidmap[type].droid_portrait_rotation_series_prefix ) + 1) - (size_t)(const void *)(Droidmap[type].droid_portrait_rotation_series_prefix ) == 1) && (__s2_len = strlen (Droidmap[type].droid_portrait_rotation_series_prefix ), __s2_len < 4) ? (__builtin_constant_p (LastImageSeriesPrefix ) && ((size_t)(const void *)((LastImageSeriesPrefix) + 1) - (size_t)(const void *)(LastImageSeriesPrefix) == 1) ? __builtin_strcmp (LastImageSeriesPrefix, Droidmap[type].droid_portrait_rotation_series_prefix ) : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (LastImageSeriesPrefix); int __result = (((const unsigned char *) (const char *) (Droidmap[type].droid_portrait_rotation_series_prefix ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (Droidmap [type].droid_portrait_rotation_series_prefix))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = ( ((const unsigned char *) (const char *) (Droidmap[type].droid_portrait_rotation_series_prefix ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (Droidmap [type].droid_portrait_rotation_series_prefix))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (LastImageSeriesPrefix , Droidmap[type].droid_portrait_rotation_series_prefix)))); } )) { |
158 | int i; |
159 | for (i = 0; i < NUMBER_OF_IMAGES_IN_DROID_PORTRAIT_ROTATION32; i++) { |
160 | delete_image(&droid_images[i]); |
161 | |
162 | sprintf(filename, "droids/%s/portrait_%04d.jpg", Droidmap[type].droid_portrait_rotation_series_prefix, i + 1); |
163 | |
164 | load_image(&droid_images[i], filename, FALSE(0)); |
165 | } |
166 | |
167 | strcpy(LastImageSeriesPrefix, Droidmap[type].droid_portrait_rotation_series_prefix); |
168 | } |
169 | |
170 | RotationIndex = (SDL_GetTicks() / 50); |
171 | |
172 | RotationIndex = |
173 | RotationIndex - (RotationIndex / NUMBER_OF_IMAGES_IN_DROID_PORTRAIT_ROTATION32) * NUMBER_OF_IMAGES_IN_DROID_PORTRAIT_ROTATION32; |
174 | |
175 | // Compute the maximum uniform scale to apply to the bot image so that it fills |
176 | // the droid portrait image, and center the image. |
177 | struct image *img = &droid_images[RotationIndex]; |
178 | float scale = min((float)Droid_Image_Window.w / (float)img->w, (float)Droid_Image_Window.h / (float)img->h)(((float)Droid_Image_Window.w / (float)img->w) > ((float )Droid_Image_Window.h / (float)img->h) ? ((float)Droid_Image_Window .h / (float)img->h) : ((float)Droid_Image_Window.w / (float )img->w) ); |
179 | moderately_finepoint pos; |
180 | pos.x = (float)PosX + ((float)Droid_Image_Window.w - (float)img->w * scale) / 2.0; |
181 | pos.y = (float)PosY + ((float)Droid_Image_Window.h - (float)img->h * scale) / 2.0; |
182 | display_image_on_screen(img, pos.x, pos.y, IMAGE_SCALE_TRANSFO(scale)set_image_transformation(scale, scale, 1.0, 1.0, 1.0, 1.0, 0)); |
183 | } |
184 | |
185 | /** |
186 | * Display infopage page of droidtype. |
187 | */ |
188 | static void show_droid_info(int droidtype) |
189 | { |
190 | SDL_Rect clip; |
191 | |
192 | SDL_SetClipRect(Screen, NULL((void*)0)); |
193 | |
194 | // Show background |
195 | blit_background("console_bg1.jpg"); |
196 | blit_background("takeover_browser.png"); |
197 | |
198 | // Show droid portrait |
199 | show_droid_picture(UNIVERSAL_COORD_W(45)(int)((float)(45) * ((float)(GameConfig . screen_width) / 640.0 )), UNIVERSAL_COORD_H(213)(int)((float)(213) * ((float)(GameConfig . screen_height) / 480.0 )), droidtype); |
200 | |
201 | // Show the droid name |
202 | SetCurrentFont(Menu_BFont); |
203 | clip.x = UNIVERSAL_COORD_W(330)(int)((float)(330) * ((float)(GameConfig . screen_width) / 640.0 )); |
204 | clip.y = UNIVERSAL_COORD_H(57)(int)((float)(57) * ((float)(GameConfig . screen_height) / 480.0 )); |
205 | clip.w = UNIVERSAL_COORD_W(200)(int)((float)(200) * ((float)(GameConfig . screen_width) / 640.0 )); |
206 | clip.h = UNIVERSAL_COORD_H(30)(int)((float)(30) * ((float)(GameConfig . screen_height) / 480.0 )); |
207 | display_text_using_line_height(D_(Droidmap[droidtype].default_short_description)(Droidmap[droidtype].default_short_description[0]!='\0'?dcgettext ("freedroidrpg-data", Droidmap[droidtype].default_short_description , 5):""), clip.x, clip.y, &clip, 1.0); |
208 | } |
209 | |
210 | /** |
211 | * Initialize text widget with a description of the specified droidtype. |
212 | */ |
213 | static void init_droid_description(struct widget_text *w, int droidtype) |
214 | { |
215 | const char *item_name; |
216 | int weapon_type; |
217 | |
218 | autostr_append(w->text, _("Unit Type %s\n")("Unit Type %s\n"[0]!='\0'?dcgettext (((void*)0), "Unit Type %s\n" , 5):""), Droidmap[droidtype].droidname); |
219 | autostr_append(w->text, _("Entry : %d\n")("Entry : %d\n"[0]!='\0'?dcgettext (((void*)0), "Entry : %d\n" , 5):""), droidtype + 1); |
220 | |
221 | if ((weapon_type = Droidmap[droidtype].weapon_item.type) >= 0) // make sure item != -1 |
222 | item_name = D_(item_specs_get_name(weapon_type))(item_specs_get_name(weapon_type)[0]!='\0'?dcgettext ("freedroidrpg-data" , item_specs_get_name(weapon_type), 5):""); // does not segfault |
223 | else |
224 | item_name = _("none")("none"[0]!='\0'?dcgettext (((void*)0), "none", 5):""); |
225 | |
226 | autostr_append(w->text, _("\nArmament : %s\n")("\nArmament : %s\n"[0]!='\0'?dcgettext (((void*)0), "\nArmament : %s\n" , 5):""), item_name); |
227 | autostr_append(w->text, _("\nCores : %d\n")("\nCores : %d\n"[0]!='\0'?dcgettext (((void*)0), "\nCores : %d\n" , 5):""), 2 + Droidmap[droidtype].class); |
228 | |
229 | |
230 | if (Me.TakeoverSuccesses[droidtype]+Me.TakeoverFailures[droidtype]) { |
231 | int success_ratio = |
232 | ((100*Me.TakeoverSuccesses[droidtype])/ |
233 | (Me.TakeoverSuccesses[droidtype]+Me.TakeoverFailures[droidtype])); |
234 | |
235 | autostr_append(w->text, _("\nTakeover Success : %2d%%\n")("\nTakeover Success : %2d%%\n"[0]!='\0'?dcgettext (((void*)0 ), "\nTakeover Success : %2d%%\n", 5):""), success_ratio); |
236 | } |
237 | |
238 | autostr_append(w->text, _("\nNotes: %s\n")("\nNotes: %s\n"[0]!='\0'?dcgettext (((void*)0), "\nNotes: %s\n" , 5):""), D_(Droidmap[droidtype].notes)(Droidmap[droidtype].notes[0]!='\0'?dcgettext ("freedroidrpg-data" , Droidmap[droidtype].notes, 5):"")); |
239 | } |
240 | |
241 | /** |
242 | * This function does the countdown where you still can changes your |
243 | * color. |
244 | */ |
245 | static void ChooseColor(enemy *target) |
246 | { |
247 | int countdown = 100; // duration in 1/10 seconds given for color choosing |
248 | int ColorChosen = FALSE(0); |
249 | char count_text[80]; |
250 | SDL_Event event; |
251 | |
252 | Uint32 prev_count_tick, count_tick_len; |
253 | |
254 | count_tick_len = 100; // countdown in 1/10 second steps |
255 | |
256 | prev_count_tick = SDL_GetTicks(); |
257 | |
258 | while (!ColorChosen) { |
259 | |
260 | // wait for next countdown tick |
261 | while (SDL_GetTicks() < prev_count_tick + count_tick_len) ; |
262 | |
263 | prev_count_tick += count_tick_len; // set for next tick |
264 | |
265 | while (SDL_PollEvent(&event)) { |
266 | |
267 | if (event.type == SDL_QUIT) { |
268 | Terminate(EXIT_SUCCESS0); |
269 | } |
270 | |
271 | if (event.type == SDL_MOUSEBUTTONDOWN) { |
272 | switch (event.button.button) { |
273 | //(clever?) hack : mouse wheel up and down behave |
274 | //exactly like LEFT and RIGHT arrow, so we mangle the event |
275 | case SDL_BUTTON_WHEELUP4: |
276 | event.type = SDL_KEYDOWN; |
277 | event.key.keysym.sym = SDLK_LEFT; |
278 | break; |
279 | case SDL_BUTTON_WHEELDOWN5: |
280 | event.type = SDL_KEYDOWN; |
281 | event.key.keysym.sym = SDLK_RIGHT; |
282 | break; |
283 | case SDL_BUTTON_LEFT1: |
284 | ColorChosen = TRUE(1); |
285 | break; |
286 | |
287 | default: |
288 | break; |
289 | } |
290 | } |
291 | |
292 | /* no else there! (mouse wheel) */ |
293 | if (event.type == SDL_KEYDOWN) { |
294 | switch (event.key.keysym.sym) { |
295 | case SDLK_RIGHT: |
296 | YourColor = PURPLE; |
297 | OpponentColor = YELLOW; |
298 | break; |
299 | case SDLK_LEFT: |
300 | YourColor = YELLOW; |
301 | OpponentColor = PURPLE; |
302 | break; |
303 | case SDLK_SPACE: |
304 | ColorChosen = TRUE(1); |
305 | break; |
306 | default: |
307 | break; |
308 | } |
309 | } |
310 | |
311 | } |
312 | |
313 | countdown--; // Count down |
314 | sprintf(count_text, _("Color-%d.%d")("Color-%d.%d"[0]!='\0'?dcgettext (((void*)0), "Color-%d.%d", 5):""), countdown/10, countdown%10); |
315 | |
316 | ShowPlayground(target); |
317 | to_show_banner(count_text, NULL((void*)0)); |
318 | our_SDL_flip_wrapper(); |
319 | |
320 | if (countdown == 0) |
321 | ColorChosen = TRUE(1); |
322 | |
323 | } // while(!ColorChosen) |
324 | |
325 | while (MouseLeftPressed()) |
326 | SDL_Delay(1); |
327 | }; // void ChooseColor ( void ) |
328 | |
329 | static void PlayGame(int countdown, enemy *target) |
330 | { |
331 | char count_text[80]; |
332 | int FinishTakeover = FALSE(0); |
333 | int row; |
334 | |
335 | Uint32 prev_count_tick, count_tick_len; /* tick vars for count-down */ |
336 | Uint32 prev_move_tick, move_tick_len; /* tick vars for motion */ |
337 | int wait_move_ticks; /* number of move-ticks to wait before "key-repeat" */ |
338 | |
339 | int up, down, set; |
340 | int up_counter, down_counter; |
341 | |
342 | SDL_Event event; |
343 | |
344 | sprintf(count_text, " "); /* Make sure a value gets assigned to count_text */ |
345 | count_tick_len = 100; /* countdown in 1/10 second steps */ |
346 | move_tick_len = 60; /* allow motion at this tick-speed in ms */ |
347 | |
348 | up = down = set = FALSE(0); |
349 | up_counter = down_counter = 0; |
350 | |
351 | wait_move_ticks = 2; |
352 | |
353 | prev_count_tick = prev_move_tick = SDL_GetTicks(); /* start tick clock */ |
354 | |
355 | while (!FinishTakeover) { |
356 | cur_time = SDL_GetTicks(); |
357 | |
358 | /* |
359 | * here we register if there have been key-press events in the |
360 | * "waiting period" between move-ticks : |
361 | */ |
362 | up = (up | UpPressed()); |
363 | down = (down | DownPressed()); |
364 | set = set | SpacePressed() | MouseLeftPressed(); |
365 | |
366 | while (SDL_PollEvent(&event)) { |
367 | if (event.type == SDL_MOUSEBUTTONDOWN) { |
368 | switch (event.button.button) { |
369 | case SDL_BUTTON_WHEELUP4: |
370 | up++; |
371 | break; |
372 | case SDL_BUTTON_WHEELDOWN5: |
373 | down++; |
374 | break; |
375 | default: |
376 | break; |
377 | } |
378 | } else if (event.type == SDL_KEYDOWN) { |
379 | /* allow for a WIN-key that gives immediate victory */ |
380 | event.key.keysym.mod &= ~(KMOD_CAPS | KMOD_NUM | KMOD_MODE); /* We want to ignore "global" modifiers. */ |
381 | if (event.key.keysym.sym == SDLK_w && (event.key.keysym.mod == (KMOD_LCTRL | KMOD_LALT))) { |
382 | LeaderColor = YourColor; /* simple as that */ |
383 | return; /* leave now, to avoid changing of LeaderColor! */ |
384 | } |
385 | } else if (event.type == SDL_QUIT) { |
386 | Terminate(EXIT_SUCCESS0); |
387 | } |
388 | } |
389 | |
390 | if (!up) |
391 | up_counter = 0; /* reset counters for released keys */ |
392 | if (!down) |
393 | down_counter = 0; |
394 | |
395 | if (cur_time > prev_count_tick + count_tick_len) { /* time to count 1 down */ |
396 | prev_count_tick += count_tick_len; /* set for next countdown tick */ |
397 | countdown--; |
398 | sprintf(count_text, _("Finish-%d.%d")("Finish-%d.%d"[0]!='\0'?dcgettext (((void*)0), "Finish-%d.%d" , 5):""), countdown/10, countdown%10); |
399 | |
400 | if (countdown == 0) |
401 | FinishTakeover = TRUE(1); |
402 | |
403 | AnimateCurrents(); /* do some animation on the active cables */ |
404 | |
405 | } |
406 | |
407 | /* if (countdown_tick has occurred) */ |
408 | /* time for movement */ |
409 | if (cur_time > prev_move_tick + move_tick_len) { |
410 | prev_move_tick += move_tick_len; /* set for next motion tick */ |
411 | AdvancedEnemyTakeoverMovements(countdown); |
412 | |
413 | if (up) { |
414 | if (!up_counter || (up_counter > wait_move_ticks)) { |
415 | // Here I have to change some things in order to make |
416 | // mouse movement work properly with the wheel... |
417 | // |
418 | // CapsuleCurRow[YourColor]--; |
419 | // |
420 | CapsuleCurRow[YourColor] -= up; |
421 | |
422 | if (CapsuleCurRow[YourColor] < 1) |
423 | CapsuleCurRow[YourColor] = NUM_LINES12; |
424 | } |
425 | up = FALSE(0); |
426 | up_counter++; |
427 | } |
428 | if (down) { |
429 | if (!down_counter || (down_counter > wait_move_ticks)) { |
430 | // Here I have to change some things in order to make |
431 | // mouse movement work properly with the wheel... |
432 | // |
433 | // CapsuleCurRow[YourColor]++; |
434 | // |
435 | CapsuleCurRow[YourColor] += down; |
436 | |
437 | if (CapsuleCurRow[YourColor] > NUM_LINES12) |
438 | CapsuleCurRow[YourColor] = 1; |
439 | } |
440 | down = FALSE(0); |
441 | down_counter++; |
442 | } |
443 | |
444 | if (set && (NumCapsules[YOU] > 0)) { |
445 | set = FALSE(0); |
446 | row = CapsuleCurRow[YourColor] - 1; |
447 | if ((row >= 0) && |
448 | (ToPlayground[YourColor][0][row] != CABLE_END) && (ActivationMap[YourColor][0][row] == INACTIVE)) { |
449 | NumCapsules[YOU]--; |
450 | CapsuleCurRow[YourColor] = 0; |
451 | ToPlayground[YourColor][0][row] = AMPLIFIER; |
452 | ActivationMap[YourColor][0][row] = ACTIVE1; |
453 | CapsuleCountdown[YourColor][0][row] = CAPSULE_COUNTDOWN40 * 2; |
454 | |
455 | Takeover_Set_Capsule_Sound(); |
456 | |
457 | if (!NumCapsules[YOU]) { |
458 | /* You placed your last capsule ? let's speed up the end */ |
459 | count_tick_len *= 0.75; |
460 | } |
461 | } /* if (row > 0 && ... ) */ |
462 | } |
463 | /* if ( set ) */ |
464 | ProcessCapsules(); /* count down the lifetime of the capsules */ |
465 | |
466 | ProcessPlayground(); |
467 | ProcessPlayground(); |
468 | ProcessPlayground(); |
469 | ProcessPlayground(); /* this has to be done several times to be sure */ |
470 | |
471 | ProcessDisplayColumn(); |
472 | |
473 | } |
474 | /* if (motion_tick has occurred) */ |
475 | ShowPlayground(target); |
476 | to_show_banner(count_text, NULL((void*)0)); |
477 | our_SDL_flip_wrapper(); |
478 | SDL_Delay(10); |
479 | } /* while !FinishTakeover */ |
480 | |
481 | /* Final countdown */ |
482 | countdown = CAPSULE_COUNTDOWN40 + 10; |
483 | |
484 | while (countdown--) { |
485 | // speed this up a little, some people get bored here... |
486 | // while ( SDL_GetTicks() < prev_count_tick + count_tick_len ) ; |
487 | // prev_count_tick += count_tick_len; |
488 | ProcessCapsules(); /* count down the lifetime of the capsules */ |
489 | ProcessCapsules(); /* do it twice this time to be faster */ |
490 | // AnimateCurrents (); |
491 | ProcessPlayground(); |
492 | ProcessPlayground(); |
493 | ProcessPlayground(); |
494 | ProcessPlayground(); /* this has to be done several times to be sure */ |
495 | ProcessDisplayColumn(); |
496 | ShowPlayground(target); |
497 | our_SDL_flip_wrapper(); |
498 | } /* while (countdown) */ |
499 | |
500 | return; |
501 | |
502 | } |
503 | |
504 | static void show_info_up_button() { |
505 | ShowGenericButtonFromList(UP_BUTTON); |
506 | } |
507 | |
508 | static void show_info_down_button() { |
509 | ShowGenericButtonFromList(DOWN_BUTTON); |
510 | } |
511 | |
512 | /** |
513 | * This function manages the whole takeover game of Tux against |
514 | * some bot. |
515 | * |
516 | * The return value is TRUE/FALSE depending on whether the game was |
517 | * finally won/lost. |
518 | * The function also writes the ratio of capsules the player needed to win (out of all of his capsules) into needed_capsules_ratio |
519 | * - Every capsule that has not been used within the game (numCapsules) is considered as not needed |
520 | * - For every conquered row that exceeds 7 (the minimal number of rows to win) one capsule is considered as not needed |
521 | */ |
522 | int droid_takeover(enemy *target, float *needed_capsules_ratio) |
523 | { |
524 | int menu_finished = FALSE(0); |
525 | int reward = 0; |
526 | SDL_Event event; |
527 | static struct widget_text droid_info; |
528 | |
529 | // Set up the droid description widget |
530 | widget_text_init(&droid_info, ""); |
531 | init_droid_description(&droid_info, target->type); |
532 | widget_set_rect(WIDGET(&droid_info)((struct widget *)&droid_info), UNIVERSAL_COORD_W(258)(int)((float)(258) * ((float)(GameConfig . screen_width) / 640.0 )), UNIVERSAL_COORD_H(107)(int)((float)(107) * ((float)(GameConfig . screen_height) / 480.0 )), UNIVERSAL_COORD_W(346)(int)((float)(346) * ((float)(GameConfig . screen_width) / 640.0 )), UNIVERSAL_COORD_H(282)(int)((float)(282) * ((float)(GameConfig . screen_height) / 480.0 ))); |
533 | droid_info.font = FPS_Display_BFont; |
534 | droid_info.content_above_func = show_info_up_button; |
535 | droid_info.content_below_func = show_info_down_button; |
536 | |
537 | // Prevent distortion of framerate by the delay coming from |
538 | // the time spent in the menu. |
539 | Activate_Conservative_Frame_Computation(); |
540 | |
541 | // We set the UserRect to full again, no matter what other windows might |
542 | // be open right now... |
543 | User_Rect.x = 0; |
544 | User_Rect.y = 0; |
545 | User_Rect.w = GameConfig.screen_width; |
546 | User_Rect.h = GameConfig.screen_height; |
547 | |
548 | while (SpacePressed() || MouseLeftPressed()) ; // make sure space is release before proceed |
549 | |
550 | SwitchBackgroundMusicTo("Bleostrada.ogg"); |
551 | |
552 | while (!menu_finished) { |
553 | show_droid_info(target->type); |
554 | widget_text_display(WIDGET(&droid_info)((struct widget *)&droid_info)); |
555 | ShowGenericButtonFromList(TAKEOVER_HELP_BUTTON); |
556 | SetCurrentFont(Para_BFont); |
557 | put_string_centered(Para_BFont, GameConfig.screen_height - 30, _("For more information, click the help button.")("For more information, click the help button."[0]!='\0'?dcgettext (((void*)0), "For more information, click the help button.", 5):"")); |
558 | blit_mouse_cursor(); |
559 | our_SDL_flip_wrapper(); |
560 | |
561 | while (SDL_PollEvent(&event)) { |
562 | |
563 | if (event.type == SDL_QUIT) { |
564 | Terminate(EXIT_SUCCESS0); |
565 | } |
566 | |
567 | if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT1) { |
568 | if (MouseCursorIsOnButton(UP_BUTTON, GetMousePos_x(), GetMousePos_y())) { |
569 | droid_info.scroll_offset--; |
570 | } else if (MouseCursorIsOnButton(DOWN_BUTTON, GetMousePos_x(), GetMousePos_y())) { |
571 | droid_info.scroll_offset++; |
572 | } else if (MouseCursorIsOnButton(DROID_SHOW_EXIT_BUTTON, GetMousePos_x(), GetMousePos_y())) { |
573 | menu_finished = TRUE(1); |
574 | } else if (MouseCursorIsOnButton(TAKEOVER_HELP_BUTTON, GetMousePos_x(), GetMousePos_y())) { |
575 | display_takeover_help(); |
576 | } |
577 | } else if (event.type == SDL_KEYDOWN |
578 | && ((event.key.keysym.sym == SDLK_SPACE) || (event.key.keysym.sym == SDLK_ESCAPE))) { |
579 | menu_finished = TRUE(1); |
580 | } |
581 | } |
582 | SDL_Delay(1); |
583 | } |
584 | |
585 | while (!(!SpacePressed() && !EscapePressed() && !MouseLeftPressed())) ; |
586 | |
587 | int player_capsules = 2 + Me.skill_level[get_program_index_with_name("Hacking")]; |
588 | max_opponent_capsules = 2 + Droidmap[target->type].class; |
589 | |
590 | if (do_takeover(player_capsules, max_opponent_capsules, 100, target)) { |
591 | /* Won takeover */ |
592 | Me.marker = target->marker; |
593 | |
594 | reward = Droidmap[target->type].experience_reward * Me.experience_factor; |
595 | Me.Experience += reward; |
596 | append_new_game_message(_("For taking control of your enemy, [s]%s[v], you receive %d experience.")("For taking control of your enemy, [s]%s[v], you receive %d experience." [0]!='\0'?dcgettext (((void*)0), "For taking control of your enemy, [s]%s[v], you receive %d experience." , 5):""), D_(target->short_description_text)(target->short_description_text[0]!='\0'?dcgettext ("freedroidrpg-data" , target->short_description_text, 5):""), reward); |
597 | |
598 | // Maybe the enemy in question was a kind of 'boss monster' or it had |
599 | // some special item, that is relevant to a mission or quest. In that |
600 | // case (like also when the bot is finally destroyed, the quest item |
601 | // should be dropped after the successful takeover process, even if the |
602 | // enemy isn't completely dead yet... |
603 | // |
604 | if (target->on_death_drop_item_code != (-1)) { |
605 | DropItemAt(target->on_death_drop_item_code, target->pos.z, target->pos.x, target->pos.y, 1); |
606 | target->on_death_drop_item_code = -1; |
607 | } |
608 | |
609 | target->faction = FACTION_SELF; |
610 | target->has_been_taken_over = TRUE(1); |
611 | |
612 | target->combat_state = WAYPOINTLESS_WANDERING; |
613 | |
614 | // Always use the AfterTakeover dialog |
615 | free(target->dialog_section_name); |
616 | target->dialog_section_name = strdup("AfterTakeover")(__extension__ (__builtin_constant_p ("AfterTakeover") && ((size_t)(const void *)(("AfterTakeover") + 1) - (size_t)(const void *)("AfterTakeover") == 1) ? (((const char *) ("AfterTakeover" ))[0] == '\0' ? (char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen ("AfterTakeover") + 1; char *__retval = (char *) malloc (__len); if (__retval != ((void*)0)) __retval = (char *) memcpy (__retval, "AfterTakeover", __len); __retval ; })) : __strdup ("AfterTakeover"))); |
617 | |
618 | // When the bot is taken over, it should not turn hostile when |
619 | // the rest of his former combat group (identified by having the |
620 | // same marker) is attacked by the Tux. |
621 | // |
622 | target->marker = 0; |
623 | Me.TakeoverSuccesses[target->type]++; |
624 | } else { |
625 | Me.energy *= 0.5; |
626 | Me.TakeoverFailures[target->type]++; |
627 | } |
628 | |
629 | clear_screen(); |
630 | |
631 | SwitchBackgroundMusicTo(CURLEVEL()(curShip.AllLevels[Me.pos.z])->Background_Song_Name); |
632 | |
633 | if (LeaderColor == YourColor) { |
634 | // set the ratio of needed capsules out of all (player) capsules |
635 | // - Every capsule that has not been used within the game (numCapsules) is considered as not needed |
636 | // - For every conquered row that exceeds 7 (the minimal number of rows to win) one capsule is considered as not needed |
637 | *needed_capsules_ratio = 1 - (float)(NumCapsules[YOU] + LeaderCapsuleCount - 7) / (float)player_capsules; |
638 | |
639 | return TRUE(1); |
640 | } else { |
641 | return FALSE(0); |
642 | } |
643 | }; // int Takeover( int enemynum ) |
644 | |
645 | /*----------------------------------------------------------------- |
646 | * This function performs the enemy movements in the takeover game, |
647 | * but it does this in an advanced way, that has not been there in |
648 | * the classic freedroid game. |
649 | *-----------------------------------------------------------------*/ |
650 | void AdvancedEnemyTakeoverMovements(const int countdown) |
651 | { |
652 | // static int Actions = 3; |
653 | static int MoveProbability = 100; |
654 | static int TurnProbability = 10; |
655 | static int SetProbability = 80; |
656 | |
657 | int action; |
658 | static int direction = 1; /* start with this direction */ |
659 | int row = CapsuleCurRow[OpponentColor] - 1; |
660 | int test_row; |
661 | int test_value; |
662 | |
663 | int BestTarget = -1; |
664 | float BestValue = (-10000); // less than any capsule can have |
665 | |
666 | int endgame = 0; |
667 | if (countdown < NumCapsules[ENEMY]*7) |
668 | endgame = 1; |
669 | |
670 | #define TAKEOVER_MOVEMENT_DEBUG1 1 |
671 | |
672 | if (NumCapsules[ENEMY] == 0) |
673 | return; |
674 | |
675 | |
676 | if (GameConfig.difficulty_level!= DIFFICULTY_EASY){ //disable AI waiting on easy |
677 | // Wait for the player to move |
678 | if ((LeaderColor!=YourColor) && ((NumCapsules[YOU]-NumCapsules[ENEMY])>=0) && (!endgame) && (NumCapsules[ENEMY]<max_opponent_capsules)) |
679 | return; |
680 | } |
681 | |
682 | // First we're going to find out which target place is |
683 | // best choice for the next capsule setting. |
684 | // |
685 | for (test_row = 0; test_row < NUM_LINES12; test_row++) { |
686 | test_value = EvaluatePosition(OpponentColor, test_row, 1, endgame) + 0.01*test_row; |
687 | if (test_value > BestValue) { |
688 | BestTarget = test_row; |
689 | BestValue = test_value; |
690 | } |
691 | } |
692 | DebugPrintf(TAKEOVER_MOVEMENT_DEBUG1, "\nBest target row found : %d.", BestTarget); |
693 | |
694 | if ((BestValue < 0.5) && (!endgame) && (LeaderColor==OpponentColor)) //it isn't worth it |
695 | return; |
696 | |
697 | // Now we can start to move into the right direction. |
698 | // Previously this was a pure random choice like |
699 | // |
700 | // action = MyRandom (Actions); |
701 | // |
702 | // but now we do it differently :) |
703 | // |
704 | if (row < BestTarget) { |
705 | direction = 1; |
706 | action = 0; |
707 | } else if (row > BestTarget) { |
708 | direction = -1; |
709 | action = 0; |
710 | } else { |
711 | action = 2; |
712 | } |
713 | |
714 | switch (action) { |
715 | case 0: /* Move along */ |
716 | if (MyRandom(100) <= MoveProbability) { |
717 | row += direction; |
718 | if (row > NUM_LINES12 - 1) |
719 | row = 0; |
720 | if (row < 0) |
721 | row = NUM_LINES12 - 1; |
722 | } |
723 | break; |
724 | |
725 | case 1: /* Turn around */ |
726 | if (MyRandom(100) <= TurnProbability) { |
727 | direction *= -1; |
728 | } |
729 | break; |
730 | case 2: /* Try to set capsule */ |
731 | if (MyRandom(100) <= SetProbability) { |
732 | if ((row >= 0) && |
733 | (ToPlayground[OpponentColor][0][row] != CABLE_END) && (ActivationMap[OpponentColor][0][row] == INACTIVE)) { |
734 | NumCapsules[ENEMY]--; |
735 | Takeover_Set_Capsule_Sound(); |
736 | ToPlayground[OpponentColor][0][row] = AMPLIFIER; |
737 | ActivationMap[OpponentColor][0][row] = ACTIVE1; |
738 | CapsuleCountdown[OpponentColor][0][row] = CAPSULE_COUNTDOWN40; |
739 | row = -1; /* For the next capsule: startpos */ |
740 | } |
741 | else |
742 | { |
743 | row += direction; |
Value stored to 'row' is never read | |
744 | return; |
745 | } |
746 | } |
747 | /* if MyRandom */ |
748 | break; |
749 | |
750 | default: |
751 | break; |
752 | |
753 | } /* switch action */ |
754 | |
755 | CapsuleCurRow[OpponentColor] = row + 1; |
756 | |
757 | return; |
758 | }; // AdvancedEnemyTakeoverMovements |
759 | |
760 | static void GetTakeoverGraphics(void) |
761 | { |
762 | static int TakeoverGraphicsAreAlreadyLoaded = FALSE(0); |
763 | struct image img = EMPTY_IMAGE{ .surface = ((void*)0) , .offset_x = 0 , .offset_y = 0 , .texture_has_been_created = 0 , .cached_transformation = { ((void*)0), 0.0, 0.0, { 0.0 , 0.0, 0.0, 0.0}, 0 } }; |
764 | int i, j; |
765 | int curx = 0, cury = 0; |
766 | SDL_Rect tmp; |
767 | |
768 | if (TakeoverGraphicsAreAlreadyLoaded) |
769 | return; |
770 | |
771 | load_image(&img, TO_BLOCK_FILE"to_elem.png", FALSE(0)); |
772 | |
773 | // Get the fill-blocks |
774 | for (i = 0; i < NUM_FILL_BLOCKS3; i++, curx += FILL_BLOCK_LEN2*16 + 2) { |
775 | Set_Rect(tmp, curx, cury, FILL_BLOCK_LEN, FILL_BLOCK_HEIGHT){(tmp).x = (curx); (tmp).y = (cury); (tmp).w = (2*16); (tmp). h = (2*7); }; |
776 | create_subimage(&img, &FillBlocks[i], &tmp); |
777 | } |
778 | |
779 | // Get the capsule blocks |
780 | for (i = 0; i < NUM_CAPS_BLOCKS3; i++, curx += CAPSULE_LEN2*7 + 2) { |
781 | Set_Rect(tmp, curx, cury, CAPSULE_LEN, CAPSULE_HEIGHT){(tmp).x = (curx); (tmp).y = (cury); (tmp).w = (2*7); (tmp).h = (2*7); }; |
782 | create_subimage(&img, &CapsuleBlocks[i], &tmp); |
783 | } |
784 | |
785 | // Get the default background color, to be used when no background picture found! |
786 | curx = 0; |
787 | cury += FILL_BLOCK_HEIGHT2*7 + 2; |
788 | |
789 | // get the game-blocks |
790 | for (j = 0; j < 2 * NUM_PHASES5; j++) { |
791 | for (i = 0; i < TO_BLOCKS11; i++) { |
792 | Set_Rect(tmp, curx, cury, TO_BLOCKLEN, TO_BLOCKHEIGHT){(tmp).x = (curx); (tmp).y = (cury); (tmp).w = (2*32); (tmp). h = (2*8); }; |
793 | create_subimage(&img, &ToGameBlocks[j * TO_BLOCKS11 + i], &tmp); |
794 | curx += TO_BLOCKLEN2*32 + 2; |
795 | } |
796 | curx = 0; |
797 | cury += TO_BLOCKHEIGHT2*8 + 2; |
798 | } |
799 | |
800 | // Get the ground, column and leader blocks |
801 | for (i = 0; i < NUM_GROUND_BLOCKS6; i++) { |
802 | Set_Rect(tmp, curx, cury, GROUNDBLOCKLEN, GROUNDBLOCKHEIGHT){(tmp).x = (curx); (tmp).y = (cury); (tmp).w = (2*23); (tmp). h = (2*8); }; |
803 | create_subimage(&img, &ToGroundBlocks[i], &tmp); |
804 | curx += GROUNDBLOCKLEN2*23 + 2; |
805 | } |
806 | cury += GROUNDBLOCKHEIGHT2*8 + 2; |
807 | curx = 0; |
808 | |
809 | // Now the rectangle for the column blocks will be set and after |
810 | // that we can create the new surface for blitting. |
811 | // |
812 | Set_Rect(tmp, curx, cury, COLUMNBLOCKLEN, COLUMNBLOCKHEIGHT){(tmp).x = (curx); (tmp).y = (cury); (tmp).w = (2*30); (tmp). h = (2*8); }; |
813 | create_subimage(&img, &ToColumnBlock, &tmp); |
814 | |
815 | curx += COLUMNBLOCKLEN2*30 + 2; |
816 | |
817 | // Now the rectangle for the leader block will be set and after |
818 | // that we can create the new surface for blitting. |
819 | // |
820 | Set_Rect(tmp, curx, cury, LEADERBLOCKLEN, LEADERBLOCKHEIGHT){(tmp).x = (curx); (tmp).y = (cury); (tmp).w = (2*30); (tmp). h = (2*19); }; |
821 | create_subimage(&img, &ToLeaderBlock, &tmp); |
822 | |
823 | free_image_surface(&img); |
824 | TakeoverGraphicsAreAlreadyLoaded = TRUE(1); |
825 | } |
826 | |
827 | /** |
828 | * Initiate the takeover game |
829 | * @param game_length game time in tenths of a second |
830 | * @param target a pointer to the enemy structure of the target. NULL means none |
831 | * @return 1 on player success, 0 on player failure |
832 | */ |
833 | int do_takeover(int player_capsules, int opponent_capsules, int game_length, enemy* target) |
834 | { |
835 | char *message; |
836 | int player_won = 0; |
837 | int FinishTakeover = FALSE(0); |
838 | int row; |
839 | int old_status; |
840 | |
841 | old_status = game_status; |
842 | |
843 | Activate_Conservative_Frame_Computation(); |
844 | |
845 | // Maybe takeover graphics haven't been loaded yet. Then we do this |
846 | // here now and for once. Later calls will be ignored inside the function. |
847 | GetTakeoverGraphics(); |
848 | |
849 | // eat pending events |
850 | input_handle(); |
851 | |
852 | while (!FinishTakeover) { |
853 | // Init Color-column and Capsule-Number for each opponent and your color |
854 | // |
855 | for (row = 0; row < NUM_LINES12; row++) { |
856 | DisplayColumn[row] = (row % 2); |
857 | CapsuleCountdown[YELLOW][0][row] = -1; |
858 | CapsuleCountdown[PURPLE][0][row] = -1; |
859 | } // for row |
860 | |
861 | YourColor = YELLOW; |
862 | OpponentColor = PURPLE; |
863 | |
864 | CapsuleCurRow[YELLOW] = 0; |
865 | CapsuleCurRow[PURPLE] = 0; |
866 | |
867 | NumCapsules[YOU] = player_capsules; |
868 | NumCapsules[ENEMY] = opponent_capsules; |
869 | InventPlayground(); |
870 | |
871 | EvaluatePlayground(); |
872 | |
873 | ShowPlayground(target); |
874 | our_SDL_flip_wrapper(); |
875 | |
876 | ChooseColor(target); |
877 | |
878 | // This following function plays the takeover game, until one |
879 | // of THREE states is reached, i.e. until YOU WON, YOU LOST |
880 | // or until DEADLOCK is reached. Well, so maybe after that |
881 | // the takeover game is finished, but if it's a deadlock, then |
882 | // the game must be played again in the next loop... |
883 | // |
884 | PlayGame(game_length, target); |
885 | |
886 | // We we evaluate the final score of the game. Maybe we're done |
887 | // already, maybe not... |
888 | // |
889 | if (LeaderColor == YourColor) { |
890 | Takeover_Game_Won_Sound(); |
891 | message = _("Complete")("Complete"[0]!='\0'?dcgettext (((void*)0), "Complete", 5):"" ); |
892 | FinishTakeover = TRUE(1); |
893 | player_won = 1; |
894 | } else if (LeaderColor == OpponentColor) { |
895 | Takeover_Game_Lost_Sound(); |
896 | message = _("Rejected")("Rejected"[0]!='\0'?dcgettext (((void*)0), "Rejected", 5):"" ); |
897 | FinishTakeover = TRUE(1); |
898 | player_won = 0; |
899 | } else { |
900 | Takeover_Game_Deadlock_Sound(); |
901 | message = _("Deadlock")("Deadlock"[0]!='\0'?dcgettext (((void*)0), "Deadlock", 5):"" ); |
902 | } |
903 | |
904 | ShowPlayground(target); |
905 | to_show_banner(message, NULL((void*)0)); |
906 | our_SDL_flip_wrapper(); |
907 | SDL_Delay(100); |
908 | |
909 | } |
910 | |
911 | game_status = old_status; |
912 | return player_won; |
913 | } |
914 | |
915 | /** |
916 | * Draws the playground for the takeover game |
917 | * @param target a pointer to the target's enemy structure. Use NULL for none |
918 | */ |
919 | static void ShowPlayground(enemy * target) |
920 | { |
921 | int i, j; |
922 | int color, player; |
923 | int block; |
924 | int xoffs, yoffs; |
925 | SDL_Rect Target_Rect; |
926 | int phase, dheight; |
927 | xoffs = User_Rect.x + (User_Rect.w - 2 * 290) / 2; |
928 | yoffs = User_Rect.y + (User_Rect.h - 2 * 140) / 2 + 30; |
929 | |
930 | phase = (int) Me.phase; |
931 | |
932 | blit_background("console_bg1.jpg"); |
933 | |
934 | static struct image bg; |
935 | if (!image_loaded(&bg)) { |
936 | load_image(&bg, "backgrounds/takeover_console.png", FALSE(0)); |
937 | } |
938 | |
939 | display_image_on_screen(&bg, GameConfig.screen_width / 2 - 340, GameConfig.screen_height / 2 - 294, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
940 | |
941 | |
942 | |
943 | if (target) { |
944 | // Find the difference of the droid's height and Tux's height. |
945 | // Tux's height is measured from the top of his head to the bottom of his feet |
946 | // This also accounts for the droid's blitting offset |
947 | struct tux_motion_class_images *current_motion_class_images = &tux_images[get_motion_class_id()]; |
948 | dheight = current_motion_class_images->part_images[PART_GROUP_FEET][0][phase].offset_y + |
949 | current_motion_class_images->part_images[PART_GROUP_FEET][0][phase].h - |
950 | current_motion_class_images->part_images[PART_GROUP_HEAD][0][phase].offset_y - |
951 | enemy_images[target->type][0][0].h - |
952 | enemy_images[target->type][0][0].offset_y; |
953 | |
954 | // Offset the droid's drawing rectangle by dheight minus 30 units. |
955 | Set_Rect(Target_Rect, xoffs + DroidStart[!YourColor].x + 50, yoffs + dheight - 80, User_Rect.w, User_Rect.h){(Target_Rect).x = (xoffs + DroidStart[!YourColor].x + 50); ( Target_Rect).y = (yoffs + dheight - 80); (Target_Rect).w = (User_Rect .w); (Target_Rect).h = (User_Rect.h); }; |
956 | PutIndividuallyShapedDroidBody(target, Target_Rect, FALSE(0), FALSE(0)); |
957 | } |
958 | // SDL_SetColorKey (Screen, 0, 0); |
959 | SDL_SetClipRect(Screen, &User_Rect); |
960 | |
961 | blit_tux(xoffs + DroidStart[YourColor].x + 20, yoffs - 25); |
962 | |
963 | Set_Rect(Target_Rect, xoffs + LEFT_OFFS_X, yoffs + LEFT_OFFS_Y, User_Rect.w, User_Rect.h){(Target_Rect).x = (xoffs + 2*10); (Target_Rect).y = (yoffs + 2*15); (Target_Rect).w = (User_Rect.w); (Target_Rect).h = (User_Rect .h); }; |
964 | |
965 | display_image_on_screen (&ToGroundBlocks[YELLOW_HIGH], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
966 | |
967 | Target_Rect.y += GROUNDBLOCKHEIGHT2*8; |
968 | |
969 | for (i = 0; i < 12; i++) { |
970 | display_image_on_screen (&ToGroundBlocks[YELLOW_MIDDLE], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
971 | Target_Rect.y += GROUNDBLOCKHEIGHT2*8; |
972 | } |
973 | |
974 | display_image_on_screen (&ToGroundBlocks[YELLOW_LOW], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
975 | |
976 | // the middle column |
977 | Set_Rect(Target_Rect, xoffs + MID_OFFS_X, yoffs + MID_OFFS_Y, 0, 0){(Target_Rect).x = (xoffs + 2*129); (Target_Rect).y = (yoffs + 2*8); (Target_Rect).w = (0); (Target_Rect).h = (0); }; |
978 | |
979 | display_image_on_screen (&ToLeaderBlock, Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
980 | |
981 | Target_Rect.y += LEADERBLOCKHEIGHT2*19; |
982 | for (i = 0; i < 12; i++, Target_Rect.y += COLUMNBLOCKHEIGHT2*8) { |
983 | display_image_on_screen (&ToColumnBlock, Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
984 | } |
985 | |
986 | // the right column |
987 | Set_Rect(Target_Rect, xoffs + RIGHT_OFFS_X, yoffs + RIGHT_OFFS_Y, 0, 0){(Target_Rect).x = (xoffs + 2*255); (Target_Rect).y = (yoffs + 2*15); (Target_Rect).w = (0); (Target_Rect).h = (0); }; |
988 | display_image_on_screen (&ToGroundBlocks[PURPLE_HIGH], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
989 | |
990 | Target_Rect.y += GROUNDBLOCKHEIGHT2*8; |
991 | |
992 | for (i = 0; i < 12; i++, Target_Rect.y += GROUNDBLOCKHEIGHT2*8) { |
993 | display_image_on_screen (&ToGroundBlocks[PURPLE_MIDDLE], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
994 | } |
995 | |
996 | display_image_on_screen (&ToGroundBlocks[PURPLE_LOW], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
997 | |
998 | // Fill the leader-LED with its color |
999 | Set_Rect(Target_Rect, xoffs + LEADERLED_X, yoffs + LEADERLED_Y, 0, 0){(Target_Rect).x = (xoffs + 2*136); (Target_Rect).y = (yoffs + 2*11); (Target_Rect).w = (0); (Target_Rect).h = (0); }; |
1000 | display_image_on_screen (&FillBlocks[LeaderColor], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
1001 | |
1002 | Target_Rect.y += FILL_BLOCK_HEIGHT2*7; |
1003 | display_image_on_screen (&FillBlocks[LeaderColor], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
1004 | |
1005 | // Fill the display column with its colors |
1006 | for (i = 0; i < NUM_LINES12; i++) { |
1007 | Set_Rect(Target_Rect, xoffs + LEDCOLUMN_X, yoffs + LEDCOLUMN_Y + i * (FILL_BLOCK_HEIGHT + 2), 0, 0){(Target_Rect).x = (xoffs + 2*136); (Target_Rect).y = (yoffs + 2*27 + i * (2*7 + 2)); (Target_Rect).w = (0); (Target_Rect). h = (0); }; |
1008 | display_image_on_screen (&FillBlocks[DisplayColumn[i]], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
1009 | } |
1010 | |
1011 | // Show the yellow playground |
1012 | for (i = 0; i < NUM_LAYERS4 - 1; i++) |
1013 | for (j = 0; j < NUM_LINES12; j++) { |
1014 | Set_Rect(Target_Rect, xoffs + PlaygroundStart[YELLOW].x + i * TO_BLOCKLEN,{(Target_Rect).x = (xoffs + PlaygroundStart[YELLOW].x + i * 2 *32); (Target_Rect).y = (yoffs + PlaygroundStart[YELLOW].y + j * 2*8); (Target_Rect).w = (0); (Target_Rect).h = (0); } |
1015 | yoffs + PlaygroundStart[YELLOW].y + j * TO_BLOCKHEIGHT, 0, 0){(Target_Rect).x = (xoffs + PlaygroundStart[YELLOW].x + i * 2 *32); (Target_Rect).y = (yoffs + PlaygroundStart[YELLOW].y + j * 2*8); (Target_Rect).w = (0); (Target_Rect).h = (0); }; |
1016 | block = ToPlayground[YELLOW][i][j] + ActivationMap[YELLOW][i][j] * TO_BLOCKS11; |
1017 | display_image_on_screen (&ToGameBlocks[block], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
1018 | } |
1019 | |
1020 | // Show the purple playground |
1021 | for (i = 0; i < NUM_LAYERS4 - 1; i++) |
1022 | for (j = 0; j < NUM_LINES12; j++) { |
1023 | Set_Rect(Target_Rect,{(Target_Rect).x = (xoffs + PlaygroundStart[PURPLE].x + (4 - i - 2) * 2*32); (Target_Rect).y = (yoffs + PlaygroundStart[PURPLE ].y + j * 2*8); (Target_Rect).w = (0); (Target_Rect).h = (0); } |
1024 | xoffs + PlaygroundStart[PURPLE].x + (NUM_LAYERS - i - 2) * TO_BLOCKLEN,{(Target_Rect).x = (xoffs + PlaygroundStart[PURPLE].x + (4 - i - 2) * 2*32); (Target_Rect).y = (yoffs + PlaygroundStart[PURPLE ].y + j * 2*8); (Target_Rect).w = (0); (Target_Rect).h = (0); } |
1025 | yoffs + PlaygroundStart[PURPLE].y + j * TO_BLOCKHEIGHT, 0, 0){(Target_Rect).x = (xoffs + PlaygroundStart[PURPLE].x + (4 - i - 2) * 2*32); (Target_Rect).y = (yoffs + PlaygroundStart[PURPLE ].y + j * 2*8); (Target_Rect).w = (0); (Target_Rect).h = (0); }; |
1026 | block = ToPlayground[PURPLE][i][j] + (NUM_PHASES5 + ActivationMap[PURPLE][i][j]) * TO_BLOCKS11; |
1027 | display_image_on_screen (&ToGameBlocks[block], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
1028 | } |
1029 | |
1030 | // Show the capsules left for each player |
1031 | for (player = 0; player < 2; player++) { |
1032 | if (player == YOU) |
1033 | color = YourColor; |
1034 | else |
1035 | color = OpponentColor; |
1036 | |
1037 | Set_Rect(Target_Rect, xoffs + CurCapsuleStart[color].x,{(Target_Rect).x = (xoffs + CurCapsuleStart[color].x); (Target_Rect ).y = (yoffs + CurCapsuleStart[color].y + CapsuleCurRow[color ] * (2*7 + 2)); (Target_Rect).w = (0); (Target_Rect).h = (0); } |
1038 | yoffs + CurCapsuleStart[color].y + CapsuleCurRow[color] * (CAPSULE_HEIGHT + 2), 0, 0){(Target_Rect).x = (xoffs + CurCapsuleStart[color].x); (Target_Rect ).y = (yoffs + CurCapsuleStart[color].y + CapsuleCurRow[color ] * (2*7 + 2)); (Target_Rect).w = (0); (Target_Rect).h = (0); }; |
1039 | if (NumCapsules[player]) { |
1040 | display_image_on_screen (&CapsuleBlocks[color], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
1041 | } |
1042 | |
1043 | for (i = 0; i < NumCapsules[player] - 1; i++) { |
1044 | Set_Rect(Target_Rect, xoffs + LeftCapsulesStart[color].x,{(Target_Rect).x = (xoffs + LeftCapsulesStart[color].x); (Target_Rect ).y = (yoffs + LeftCapsulesStart[color].y + i * 2*7); (Target_Rect ).w = (0); (Target_Rect).h = (0); } |
1045 | yoffs + LeftCapsulesStart[color].y + i * CAPSULE_HEIGHT, 0, 0){(Target_Rect).x = (xoffs + LeftCapsulesStart[color].x); (Target_Rect ).y = (yoffs + LeftCapsulesStart[color].y + i * 2*7); (Target_Rect ).w = (0); (Target_Rect).h = (0); }; |
1046 | display_image_on_screen (&CapsuleBlocks[color], Target_Rect.x, Target_Rect.y, IMAGE_NO_TRANSFOset_image_transformation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0)); |
1047 | } // for capsules |
1048 | } // for player |
1049 | |
1050 | return; |
1051 | |
1052 | }; // ShowPlayground |
1053 | |
1054 | /*----------------------------------------------------------------- |
1055 | * @Desc: Clears Playground (and ActivationMap) to default start-values |
1056 | * @Ret: void |
1057 | * |
1058 | *-----------------------------------------------------------------*/ |
1059 | void ClearPlayground(void) |
1060 | { |
1061 | int color, layer, row; |
1062 | |
1063 | for (color = YELLOW; color < TO_COLORS2; color++) |
1064 | for (layer = 0; layer < NUM_LAYERS4; layer++) |
1065 | for (row = 0; row < NUM_LINES12; row++) { |
1066 | ActivationMap[color][layer][row] = INACTIVE; |
1067 | if (layer < TO_COLORS2 - 1) |
1068 | ToPlayground[color][layer][row] = CABLE; |
1069 | else |
1070 | ToPlayground[color][layer][row] = INACTIVE; |
1071 | } |
1072 | |
1073 | for (row = 0; row < NUM_LINES12; row++) |
1074 | DisplayColumn[row] = row % 2; |
1075 | |
1076 | }; // void ClearPlayground ( void ) |
1077 | |
1078 | /* ----------------------------------------------------------------- |
1079 | * This function generates a random playground for the takeover game |
1080 | * ----------------------------------------------------------------- */ |
1081 | void InventPlayground(void) |
1082 | { |
1083 | int anElement; |
1084 | int newElement; |
1085 | int row, layer; |
1086 | int color = YELLOW; |
1087 | |
1088 | // first clear the playground: we depend on this !! |
1089 | // |
1090 | ClearPlayground(); |
1091 | |
1092 | for (color = YELLOW; color < TO_COLORS2; color++) { |
1093 | for (layer = 1; layer < NUM_LAYERS4 - 1; layer++) { |
1094 | for (row = 0; row < NUM_LINES12; row++) { |
1095 | if (ToPlayground[color][layer][row] != CABLE) |
1096 | continue; |
1097 | |
1098 | newElement = MyRandom(TO_ELEMENTS6 - 1); |
1099 | if (MyRandom(MAX_PROB100) > ElementProb[newElement]) { |
1100 | row--; |
1101 | continue; |
1102 | } |
1103 | |
1104 | switch (newElement) { |
1105 | case EL_CABLE: /* has not to be set any more */ |
1106 | anElement = ToPlayground[color][layer - 1][row]; |
1107 | if (BlockClass[anElement] == NON_CONNECTOR1) |
1108 | ToPlayground[color][layer][row] = EMPTY; |
1109 | break; |
1110 | |
1111 | case EL_CABLE_END: |
1112 | anElement = ToPlayground[color][layer - 1][row]; |
1113 | if (BlockClass[anElement] == NON_CONNECTOR1) |
1114 | ToPlayground[color][layer][row] = EMPTY; |
1115 | else |
1116 | ToPlayground[color][layer][row] = CABLE_END; |
1117 | break; |
1118 | |
1119 | case EL_AMPLIFIER: |
1120 | anElement = ToPlayground[color][layer - 1][row]; |
1121 | if (BlockClass[anElement] == NON_CONNECTOR1) |
1122 | ToPlayground[color][layer][row] = EMPTY; |
1123 | else |
1124 | ToPlayground[color][layer][row] = AMPLIFIER; |
1125 | break; |
1126 | |
1127 | case EL_COLOR_EXCHANGER: |
1128 | if (layer != 2) { /* only existing on layer 2 */ |
1129 | row--; |
1130 | continue; |
1131 | } |
1132 | |
1133 | anElement = ToPlayground[color][layer - 1][row]; |
1134 | if (BlockClass[anElement] == NON_CONNECTOR1) |
1135 | ToPlayground[color][layer][row] = EMPTY; |
1136 | else |
1137 | ToPlayground[color][layer][row] = COLOR_EXCHANGER; |
1138 | break; |
1139 | |
1140 | case EL_SEPARATOR: |
1141 | if (row > NUM_LINES12 - 3) { |
1142 | /* try again */ |
1143 | row--; |
1144 | break; |
1145 | } |
1146 | |
1147 | anElement = ToPlayground[color][layer - 1][row + 1]; |
1148 | if (BlockClass[anElement] == NON_CONNECTOR1) { |
1149 | /* try again */ |
1150 | row--; |
1151 | break; |
1152 | } |
1153 | |
1154 | /* don't destroy branch in prev. layer */ |
1155 | anElement = ToPlayground[color][layer - 1][row]; |
1156 | if (anElement == SEPARATOR_H || anElement == SEPARATOR_L) { |
1157 | row--; |
1158 | break; |
1159 | } |
1160 | anElement = ToPlayground[color][layer - 1][row + 2]; |
1161 | if (anElement == SEPARATOR_H || anElement == SEPARATOR_L) { |
1162 | row--; |
1163 | break; |
1164 | } |
1165 | |
1166 | /* cut off cables in last layer, if any */ |
1167 | anElement = ToPlayground[color][layer - 1][row]; |
1168 | if (BlockClass[anElement] == CONNECTOR0) |
1169 | ToPlayground[color][layer - 1][row] = CABLE_END; |
1170 | |
1171 | anElement = ToPlayground[color][layer - 1][row + 2]; |
1172 | if (BlockClass[anElement] == CONNECTOR0) |
1173 | ToPlayground[color][layer - 1][row + 2] = CABLE_END; |
1174 | |
1175 | /* set the branch itself */ |
1176 | ToPlayground[color][layer][row] = SEPARATOR_H; |
1177 | ToPlayground[color][layer][row + 1] = SEPARATOR_M; |
1178 | ToPlayground[color][layer][row + 2] = SEPARATOR_L; |
1179 | |
1180 | row += 2; |
1181 | break; |
1182 | |
1183 | case EL_GATE: |
1184 | if (row > NUM_LINES12 - 3) { |
1185 | /* try again */ |
1186 | row--; |
1187 | break; |
1188 | } |
1189 | |
1190 | anElement = ToPlayground[color][layer - 1][row]; |
1191 | if (BlockClass[anElement] == NON_CONNECTOR1) { |
1192 | /* try again */ |
1193 | row--; |
1194 | break; |
1195 | } |
1196 | anElement = ToPlayground[color][layer - 1][row + 2]; |
1197 | if (BlockClass[anElement] == NON_CONNECTOR1) { |
1198 | /* try again */ |
1199 | row--; |
1200 | break; |
1201 | } |
1202 | |
1203 | /* cut off cables in last layer, if any */ |
1204 | anElement = ToPlayground[color][layer - 1][row + 1]; |
1205 | if (BlockClass[anElement] == CONNECTOR0) |
1206 | ToPlayground[color][layer - 1][row + 1] = CABLE_END; |
1207 | |
1208 | /* set the GATE itself */ |
1209 | ToPlayground[color][layer][row] = GATE_H; |
1210 | ToPlayground[color][layer][row + 1] = GATE_M; |
1211 | ToPlayground[color][layer][row + 2] = GATE_L; |
1212 | |
1213 | row += 2; |
1214 | break; |
1215 | |
1216 | default: |
1217 | row--; |
1218 | break; |
1219 | |
1220 | } /* switch NewElement */ |
1221 | |
1222 | } /* for row */ |
1223 | |
1224 | } /* for layer */ |
1225 | |
1226 | } /* for color */ |
1227 | |
1228 | } /* InventPlayground */ |
1229 | |
1230 | /* ----------------------------------------------------------------- |
1231 | * This function generates a random playground for the takeover game |
1232 | * ----------------------------------------------------------------- */ |
1233 | void EvaluatePlayground(void) |
1234 | { |
1235 | int newElement; |
1236 | int row, layer; |
1237 | int color = YELLOW; |
1238 | float ScoreFound[TO_COLORS2]; |
1239 | |
1240 | #define EVALUATE_PLAYGROUND_DEBUG1 1 |
1241 | |
1242 | for (color = YELLOW; color < TO_COLORS2; color++) { |
1243 | |
1244 | DebugPrintf(EVALUATE_PLAYGROUND_DEBUG1, "\n----------------------------------------------------------------------\n\ |
1245 | Starting to evaluate side nr. %d. Results displayed below:\n", color); |
1246 | ScoreFound[color] = 0; |
1247 | |
1248 | for (layer = 1; layer < NUM_LAYERS4 - 1; layer++) { |
1249 | for (row = 0; row < NUM_LINES12; row++) { |
1250 | |
1251 | // we examine this particular spot |
1252 | newElement = ToPlayground[color][layer][row]; |
1253 | |
1254 | switch (newElement) { |
1255 | case CABLE: /* has not to be set any more */ |
1256 | case EMPTY: |
1257 | break; |
1258 | |
1259 | case CABLE_END: |
1260 | DebugPrintf(EVALUATE_PLAYGROUND_DEBUG1, "CABLE_END found --> score -= 1.0\n"); |
1261 | ScoreFound[color] -= 1.0; |
1262 | break; |
1263 | |
1264 | case AMPLIFIER: |
1265 | DebugPrintf(EVALUATE_PLAYGROUND_DEBUG1, "AMPLIFIER found --> score += 0.5\n"); |
1266 | ScoreFound[color] += 0.5; |
1267 | break; |
1268 | |
1269 | case COLOR_EXCHANGER: |
1270 | DebugPrintf(EVALUATE_PLAYGROUND_DEBUG1, "COLOR_EXCHANGER found --> score -= 1.5\n"); |
1271 | ScoreFound[color] -= 1.5; |
1272 | break; |
1273 | |
1274 | case SEPARATOR_H: |
1275 | case SEPARATOR_L: |
1276 | case SEPARATOR_M: |
1277 | DebugPrintf(EVALUATE_PLAYGROUND_DEBUG1, "SEPARATOR found --> score += 1.0\n"); |
1278 | ScoreFound[color] += 1.0; |
1279 | break; |
1280 | |
1281 | case GATE_M: |
1282 | case GATE_L: |
1283 | case GATE_H: |
1284 | DebugPrintf(EVALUATE_PLAYGROUND_DEBUG1, "GATE found --> score -= 1.0\n"); |
1285 | ScoreFound[color] -= 1.0; |
1286 | break; |
1287 | |
1288 | default: |
1289 | DebugPrintf(EVALUATE_PLAYGROUND_DEBUG1, "UNHANDLED TILE FOUND!!\n"); |
1290 | break; |
1291 | |
1292 | } /* switch NewElement */ |
1293 | |
1294 | } /* for row */ |
1295 | |
1296 | } /* for layer */ |
1297 | |
1298 | DebugPrintf(EVALUATE_PLAYGROUND_DEBUG1, "\nResult for this side: %f.\n", ScoreFound[color]); |
1299 | |
1300 | } /* for color */ |
1301 | |
1302 | DebugPrintf(EVALUATE_PLAYGROUND_DEBUG1, "\n----------------------------------------------------------------------\n"); |
1303 | |
1304 | }; // EvaluatePlayground |
1305 | |
1306 | /* ----------------------------------------------------------------- |
1307 | * This function Evaluates the AI side of the board for the takeover game |
1308 | * ----------------------------------------------------------------- */ |
1309 | float EvaluatePosition(const int color, const int row, const int layer, const int endgame) |
1310 | { |
1311 | int player = YOU; |
1312 | if (color != YourColor) |
1313 | player = ENEMY; |
1314 | |
1315 | int opp_color = YELLOW; |
1316 | if (opp_color == color) |
1317 | opp_color = PURPLE; |
1318 | |
1319 | int newElement; |
1320 | // float ScoreFound [ TO_COLORS ]; |
1321 | |
1322 | #define EVAL_DEBUG1 1 |
1323 | |
1324 | DebugPrintf(EVAL_DEBUG1, "\nEvaluatePlaygound ( %d , %d , %d ) called: ", color, row, layer); |
1325 | |
1326 | if (layer == NUM_LAYERS4 - 1) { |
1327 | DebugPrintf(EVAL_DEBUG1, "End layer reached..."); |
1328 | if (IsActive(color, row)) { |
1329 | DebugPrintf(EVAL_DEBUG1, "same color already active... returning 0.01 "); |
1330 | return (0.01*EvaluateCenterPosition(opp_color, row, layer, endgame)); |
1331 | } else if (DisplayColumn[row] == color) { |
1332 | DebugPrintf(EVAL_DEBUG1, "same color... returning 0.05 "); |
1333 | return (0.05*EvaluateCenterPosition(opp_color, row, layer, endgame)); |
1334 | } else if (IsActive(opp_color, row)) { |
1335 | DebugPrintf(EVAL_DEBUG1, "different color, but active... returning 9 "); |
1336 | if (endgame) |
1337 | return (90*EvaluateCenterPosition(opp_color, row, layer, endgame)); |
1338 | else |
1339 | return (8*EvaluateCenterPosition(opp_color, row, layer, endgame)); |
1340 | } else { |
1341 | DebugPrintf(EVAL_DEBUG1, "different color... returning 10 "); |
1342 | if (endgame) |
1343 | return (100*EvaluateCenterPosition(opp_color, row, layer, endgame)); |
1344 | else |
1345 | return (10*EvaluateCenterPosition(opp_color, row, layer, endgame)); |
1346 | } |
1347 | } |
1348 | |
1349 | if (ActivationMap[color][layer][row] == ACTIVE1) { return (0); } |
1350 | |
1351 | newElement = ToPlayground[color][layer][row]; |
1352 | |
1353 | switch (newElement) { |
1354 | case CABLE: /* has not to be set any more */ |
1355 | DebugPrintf(EVAL_DEBUG1, "CABLE reached... continuing..."); |
1356 | return (EvaluatePosition(color, row, layer + 1, endgame)); |
1357 | |
1358 | case AMPLIFIER: |
1359 | DebugPrintf(EVAL_DEBUG1, "AMPLIFIER reached... continuing..."); |
1360 | return ((1 + (0.2 * NumCapsules[player])) * EvaluatePosition(color, row, layer + 1, endgame)); |
1361 | break; |
1362 | |
1363 | case COLOR_EXCHANGER: |
1364 | DebugPrintf(EVAL_DEBUG1, "COLOR_EXCHANGER reached... continuing..."); |
1365 | return (-1.5 * EvaluatePosition(color, row, layer + 1, endgame)); |
1366 | break; |
1367 | |
1368 | case SEPARATOR_M: |
1369 | DebugPrintf(EVAL_DEBUG1, "SEPARATOR reached... double-continuing..."); |
1370 | return (EvaluatePosition(color, row + 1, layer + 1, endgame) + EvaluatePosition(color, row - 1, layer + 1, endgame)); |
1371 | break; |
1372 | |
1373 | case GATE_H: |
1374 | DebugPrintf(EVAL_DEBUG1, "GATE reached... stopping...\n"); |
1375 | if (ActivationMap[color][layer][row + 2] >= ACTIVE1) { |
1376 | return (5 * EvaluatePosition(color, row + 1, layer + 1, endgame)); |
1377 | } else if (endgame) { |
1378 | return (0.5 * EvaluatePosition(color, row + 1, layer + 1, endgame)); |
1379 | } else { |
1380 | return (0.3 * EvaluatePosition(color, row + 1, layer + 1, endgame)); |
1381 | } |
1382 | break; |
1383 | |
1384 | case GATE_L: |
1385 | DebugPrintf(EVAL_DEBUG1, "GATE reached... stopping...\n"); |
1386 | if (ActivationMap[color][layer][row - 2] >= ACTIVE1) { |
1387 | return (5 * EvaluatePosition(color, row - 1, layer + 1, endgame)); |
1388 | } else if (endgame) { |
1389 | return (0.5 * EvaluatePosition(color, row - 1, layer + 1, endgame)); |
1390 | } else { |
1391 | return (0.3 * EvaluatePosition(color, row - 1, layer + 1, endgame)); |
1392 | } |
1393 | break; |
1394 | //treat the following cases the same: |
1395 | case EMPTY: |
1396 | case CABLE_END: |
1397 | case SEPARATOR_H: |
1398 | case SEPARATOR_L: |
1399 | case GATE_M: |
1400 | return (0); |
1401 | break; |
1402 | default: |
1403 | DebugPrintf(EVAL_DEBUG1, "\nUNHANDLED TILE reached\n"); |
1404 | break; |
1405 | |
1406 | } |
1407 | return (0); |
1408 | |
1409 | }; |
1410 | |
1411 | /* ----------------------------------------------------------------- |
1412 | * This function Evaluates the Player side of the board from AI perspective |
1413 | * ----------------------------------------------------------------- */ |
1414 | float EvaluateCenterPosition(const int color, const int row, const int layer, const int endgame) |
1415 | { |
1416 | int player = YOU; //should match the color owner (and be opposite the AI) |
1417 | if (color != YourColor) |
1418 | player = ENEMY; |
1419 | |
1420 | int newElement; |
1421 | |
1422 | if (layer == 1) { |
1423 | return (1); //hit the player's end |
1424 | } |
1425 | |
1426 | newElement = ToPlayground[color][layer][row]; |
1427 | |
1428 | switch (newElement) { |
1429 | case CABLE: // has not to be set any more |
1430 | return (EvaluateCenterPosition(color, row, layer - 1, endgame)); |
1431 | case AMPLIFIER: |
1432 | if (ActivationMap[color][layer+1][row] >= ACTIVE1) { //very low hope to take this over |
1433 | return (0.06); |
1434 | } else if (endgame) { |
1435 | return (1); |
1436 | } else { |
1437 | return ((1 - (0.1 * NumCapsules[player])) * EvaluateCenterPosition(color, row, layer - 1, endgame)); |
1438 | } |
1439 | break; |
1440 | case SEPARATOR_H: //correctly evaluating this may lead to an infinite loop, using 0.5 |
1441 | if ((NumCapsules[player]>0) && (!endgame)) |
1442 | return ((0.53 - (0.02 * NumCapsules[player])) * EvaluateCenterPosition(color, row - 1, layer - 1, endgame) ); |
1443 | else |
1444 | return (EvaluateCenterPosition(color, row - 1, layer - 1, endgame)); |
1445 | break; |
1446 | case SEPARATOR_L: |
1447 | if ((NumCapsules[player]>0) && (!endgame)) |
1448 | return ((0.53 - (0.02 * NumCapsules[player])) * EvaluateCenterPosition(color, row + 1, layer - 1, endgame) ); |
1449 | else |
1450 | return (EvaluateCenterPosition(color, row + 1, layer - 1, endgame)); |
1451 | break; |
1452 | |
1453 | case GATE_M: |
1454 | if (!endgame) |
1455 | return ((0.5 + (0.09 * NumCapsules[player])) * (EvaluateCenterPosition(color, row + 1, layer - 1, endgame) + EvaluateCenterPosition(color, row - 1, layer - 1, endgame))); |
1456 | else |
1457 | return (1); |
1458 | break; |
1459 | |
1460 | //Following cases act the same: |
1461 | case COLOR_EXCHANGER: |
1462 | case EMPTY: |
1463 | case CABLE_END: |
1464 | case SEPARATOR_M: |
1465 | case GATE_H: |
1466 | case GATE_L: |
1467 | if (!endgame) |
1468 | return (1 + (0.2 * NumCapsules[player])); |
1469 | else |
1470 | return (1); |
1471 | break; |
1472 | default: |
1473 | DebugPrintf(EVAL_DEBUG1, "\nUNHANDLED TILE reached\n"); |
1474 | break; |
1475 | } |
1476 | |
1477 | return (0); |
1478 | |
1479 | }; |
1480 | |
1481 | /*----------------------------------------------------------------- |
1482 | * @Desc: process the playground following its intrinsic logic |
1483 | * |
1484 | * @Ret: void |
1485 | * |
1486 | *-----------------------------------------------------------------*/ |
1487 | void ProcessPlayground(void) |
1488 | { |
1489 | int color, layer, row; |
1490 | int TurnActive = FALSE(0); |
1491 | |
1492 | for (color = YELLOW; color < TO_COLORS2; color++) { |
1493 | for (layer = 1; layer < NUM_LAYERS4; layer++) { |
1494 | for (row = 0; row < NUM_LINES12; row++) { |
1495 | if (layer == NUM_LAYERS4 - 1) { |
1496 | if (IsActive(color, row)) |
1497 | ActivationMap[color][layer][row] = ACTIVE1; |
1498 | else |
1499 | ActivationMap[color][layer][row] = INACTIVE; |
1500 | |
1501 | continue; |
1502 | } |
1503 | /* if last layer */ |
1504 | TurnActive = FALSE(0); |
1505 | |
1506 | switch (ToPlayground[color][layer][row]) { |
1507 | case COLOR_EXCHANGER: |
1508 | case SEPARATOR_M: |
1509 | case GATE_H: |
1510 | case GATE_L: |
1511 | case CABLE: |
1512 | if (ActivationMap[color][layer - 1][row] >= ACTIVE1) |
1513 | TurnActive = TRUE(1); |
1514 | break; |
1515 | |
1516 | case AMPLIFIER: |
1517 | if (ActivationMap[color][layer - 1][row] >= ACTIVE1) |
1518 | TurnActive = TRUE(1); |
1519 | |
1520 | // additional enforcers stay active by themselves... |
1521 | if (ActivationMap[color][layer][row] >= ACTIVE1) |
1522 | TurnActive = TRUE(1); |
1523 | |
1524 | break; |
1525 | |
1526 | case CABLE_END: |
1527 | break; |
1528 | |
1529 | case SEPARATOR_H: |
1530 | if (ActivationMap[color][layer][row + 1] >= ACTIVE1) |
1531 | TurnActive = TRUE(1); |
1532 | break; |
1533 | |
1534 | case SEPARATOR_L: |
1535 | if (ActivationMap[color][layer][row - 1] >= ACTIVE1) |
1536 | TurnActive = TRUE(1); |
1537 | break; |
1538 | |
1539 | case GATE_M: |
1540 | if ((ActivationMap[color][layer][row - 1] >= ACTIVE1) |
1541 | && (ActivationMap[color][layer][row + 1] >= ACTIVE1)) |
1542 | TurnActive = TRUE(1); |
1543 | |
1544 | break; |
1545 | |
1546 | default: |
1547 | break; |
1548 | } /* switch */ |
1549 | |
1550 | if (TurnActive) { |
1551 | if (ActivationMap[color][layer][row] == INACTIVE) |
1552 | ActivationMap[color][layer][row] = ACTIVE1; |
1553 | } else |
1554 | ActivationMap[color][layer][row] = INACTIVE; |
1555 | |
1556 | } /* for row */ |
1557 | |
1558 | } /* for layer */ |
1559 | |
1560 | } /* for color */ |
1561 | |
1562 | return; |
1563 | }; // void ProcessPlayground ( void ) |
1564 | |
1565 | /** |
1566 | * This function sets the correct values for the status column in the |
1567 | * middle of the takeover game field. |
1568 | * Blinking LEDs are realized here as well. |
1569 | */ |
1570 | void ProcessDisplayColumn(void) |
1571 | { |
1572 | static int CLayer = 3; /* the connection-layer to the Column */ |
1573 | static int flicker_color = 0; |
1574 | int row; |
1575 | int YellowCounter, PurpleCounter; |
1576 | |
1577 | flicker_color = !flicker_color; |
1578 | |
1579 | for (row = 0; row < NUM_LINES12; row++) { |
1580 | // unquestioned yellow |
1581 | if ((ActivationMap[YELLOW][CLayer][row] >= ACTIVE1) && (ActivationMap[PURPLE][CLayer][row] == INACTIVE)) { |
1582 | // change color? |
1583 | if (ToPlayground[YELLOW][CLayer - 1][row] == COLOR_EXCHANGER) |
1584 | DisplayColumn[row] = PURPLE; |
1585 | else |
1586 | DisplayColumn[row] = YELLOW; |
1587 | continue; |
1588 | } |
1589 | // clearly purple |
1590 | if ((ActivationMap[YELLOW][CLayer][row] == INACTIVE) && (ActivationMap[PURPLE][CLayer][row] >= ACTIVE1)) { |
1591 | // change color? |
1592 | if (ToPlayground[PURPLE][CLayer - 1][row] == COLOR_EXCHANGER) |
1593 | DisplayColumn[row] = YELLOW; |
1594 | else |
1595 | DisplayColumn[row] = PURPLE; |
1596 | |
1597 | continue; |
1598 | } |
1599 | // undecided: flimmering |
1600 | if ((ActivationMap[YELLOW][CLayer][row] >= ACTIVE1) && (ActivationMap[PURPLE][CLayer][row] >= ACTIVE1)) { |
1601 | // change color? |
1602 | if ((ToPlayground[YELLOW][CLayer - 1][row] == COLOR_EXCHANGER) && |
1603 | (ToPlayground[PURPLE][CLayer - 1][row] != COLOR_EXCHANGER)) |
1604 | DisplayColumn[row] = PURPLE; |
1605 | else if ((ToPlayground[YELLOW][CLayer - 1][row] != COLOR_EXCHANGER) && |
1606 | (ToPlayground[PURPLE][CLayer - 1][row] == COLOR_EXCHANGER)) |
1607 | DisplayColumn[row] = YELLOW; |
1608 | else { |
1609 | if (flicker_color == 0) |
1610 | DisplayColumn[row] = YELLOW; |
1611 | else |
1612 | DisplayColumn[row] = PURPLE; |
1613 | } /* if - else if - else */ |
1614 | |
1615 | } |
1616 | /* if undecided */ |
1617 | } /* for */ |
1618 | |
1619 | // evaluate the winning color |
1620 | YellowCounter = 0; |
1621 | PurpleCounter = 0; |
1622 | for (row = 0; row < NUM_LINES12; row++) |
1623 | if (DisplayColumn[row] == YELLOW) |
1624 | YellowCounter++; |
1625 | else |
1626 | PurpleCounter++; |
1627 | |
1628 | LeaderCapsuleCount = (PurpleCounter > YellowCounter) ? PurpleCounter : YellowCounter; |
1629 | if (PurpleCounter < YellowCounter) |
1630 | LeaderColor = YELLOW; |
1631 | else if (PurpleCounter > YellowCounter) |
1632 | LeaderColor = PURPLE; |
1633 | else |
1634 | LeaderColor = DRAW; |
1635 | |
1636 | return; |
1637 | }; // void ProcessDisplayColumn |
1638 | |
1639 | /** |
1640 | * This function does the countdown of the capsules and kills them if |
1641 | * they are too old. |
1642 | */ |
1643 | void ProcessCapsules(void) |
1644 | { |
1645 | int row; |
1646 | int color; |
1647 | |
1648 | for (color = YELLOW; color <= PURPLE; color++) |
1649 | for (row = 0; row < NUM_LINES12; row++) { |
1650 | if (CapsuleCountdown[color][0][row] > 0) |
1651 | CapsuleCountdown[color][0][row]--; |
1652 | |
1653 | if (CapsuleCountdown[color][0][row] == 0) { |
1654 | CapsuleCountdown[color][0][row] = -1; |
1655 | ActivationMap[color][0][row] = INACTIVE; |
1656 | ToPlayground[color][0][row] = CABLE; |
1657 | } |
1658 | |
1659 | } /* for row */ |
1660 | |
1661 | }; // void ProcessCapsules ( void ) |
1662 | |
1663 | /** |
1664 | * This function tells, whether a Column-connection is active or not. |
1665 | * It returns TRUE or FALSE accordingly. |
1666 | */ |
1667 | int IsActive(int color, int row) |
1668 | { |
1669 | int CLayer = 3; /* the connective Layer */ |
1670 | int TestElement = ToPlayground[color][CLayer - 1][row]; |
1671 | |
1672 | if ((ActivationMap[color][CLayer - 1][row] >= ACTIVE1) && (BlockClass[TestElement] == CONNECTOR0)) |
1673 | return TRUE(1); |
1674 | else |
1675 | return FALSE(0); |
1676 | } /* IsActive */ |
1677 | |
1678 | /* ----------------------------------------------------------------- |
1679 | * This function animates the active cables: this is done by cycling |
1680 | * over the active phases ACTIVE1-ACTIVE3, which are represented by |
1681 | * different pictures in the playground |
1682 | * ----------------------------------------------------------------- */ |
1683 | void AnimateCurrents(void) |
1684 | { |
1685 | int color, layer, row; |
1686 | |
1687 | for (color = YELLOW; color <= PURPLE; color++) |
1688 | for (layer = 0; layer < NUM_LAYERS4; layer++) |
1689 | for (row = 0; row < NUM_LINES12; row++) |
1690 | if (ActivationMap[color][layer][row] >= ACTIVE1) { |
1691 | ActivationMap[color][layer][row]++; |
1692 | if (ActivationMap[color][layer][row] == NUM_PHASES5) |
1693 | ActivationMap[color][layer][row] = ACTIVE1; |
1694 | } |
1695 | |
1696 | return; |
1697 | }; // void AnimateCurrents (void) |
1698 | |
1699 | /** |
1700 | * |
1701 | * |
1702 | */ |
1703 | void to_show_banner(const char *left, const char *right) |
1704 | { |
1705 | char left_box[LEFT_TEXT_LEN20 + 10]; |
1706 | char right_box[RIGHT_TEXT_LEN6 + 10]; |
1707 | int left_len, right_len; // the actual string lengths |
1708 | |
1709 | // At first the text is prepared. This can't hurt. |
1710 | // we will decide whether to display it or not later... |
1711 | // |
1712 | |
1713 | if (left == NULL((void*)0)) |
1714 | left = "0"; |
1715 | |
1716 | if (right == NULL((void*)0)) { |
1717 | right = ""; |
1718 | } |
1719 | // Now fill in the text |
1720 | left_len = strlen(left); |
1721 | if (left_len > LEFT_TEXT_LEN20) { |
1722 | printf("\nWarning: String %s too long for Left Infoline!!", left); |
1723 | Terminate(EXIT_FAILURE1); |
1724 | } |
1725 | right_len = strlen(right); |
1726 | if (right_len > RIGHT_TEXT_LEN6) { |
1727 | printf("\nWarning: String %s too long for Right Infoline!!", right); |
1728 | Terminate(EXIT_FAILURE1); |
1729 | } |
1730 | // Now prepare the left/right text-boxes |
1731 | memset(left_box, ' ', LEFT_TEXT_LEN20); // pad with spaces |
1732 | memset(right_box, ' ', RIGHT_TEXT_LEN6); |
1733 | |
1734 | strncpy(left_box, left, left_len)__builtin_strncpy (left_box, left, left_len); // this drops terminating \0 ! |
1735 | strncpy(right_box, right, right_len)__builtin_strncpy (right_box, right, right_len); // this drops terminating \0 ! |
1736 | |
1737 | left_box[LEFT_TEXT_LEN20] = '\0'; // that's right, we want padding! |
1738 | right_box[RIGHT_TEXT_LEN6] = '\0'; |
1739 | |
1740 | // Now the text should be ready and its |
1741 | // time to display it... |
1742 | DebugPrintf(2, "Takeover said: %s -- %s\n", left_box, right_box); |
1743 | SetCurrentFont(Para_BFont); |
1744 | display_text(left_box, LEFT_INFO_X(13*2), LEFT_INFO_Y(10*2), NULL((void*)0)); |
1745 | display_text(right_box, RIGHT_INFO_X(242*2), RIGHT_INFO_Y(8*2), NULL((void*)0)); |
1746 | |
1747 | }; // void to_show_banner (const char* left, const char* right) |
1748 | |
1749 | #undef _takeover_c |