1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <SDL2/SDL.h>
4 #include "utils/log.h"
5 #include "utils/random.h"
6 #include "video/video.h"
7 #include "resources/ids.h"
8 #include "game/gui/text_render.h"
9 #include "resources/languages.h"
10 #include "game/protos/scene.h"
11 #include "game/scenes/vs.h"
12 #include "game/utils/settings.h"
13 #include "game/gui/menu_background.h"
14 #include "game/gui/dialog.h"
15 #include "game/game_state.h"
16 #include "controller/controller.h"
17 #include "controller/keyboard.h"
18 
19 void cb_vs_spawn_object(object *parent, int id, vec2i pos, int g, void *userdata);
20 void cb_vs_destroy_object(object *parent, int id, void *userdata);
21 
22 typedef struct vs_local_t {
23     object player1_portrait;
24     object player2_portrait;
25     object player1_har;
26     object player2_har;
27     surface arena_select_bg;
28     object arena_select;
29     int arena;
30     char vs_str[128];
31     dialog quit_dialog;
32     dialog too_pathetic_dialog;
33 } vs_local;
34 
vs_is_netplay(scene * scene)35 int vs_is_netplay(scene *scene) {
36     if(game_state_get_player(scene->gs, 0)->ctrl->type == CTRL_TYPE_NETWORK ||
37        game_state_get_player(scene->gs, 1)->ctrl->type == CTRL_TYPE_NETWORK) {
38         return 1;
39     }
40     return 0;
41 }
42 
vs_is_singleplayer(scene * scene)43 int vs_is_singleplayer(scene *scene) {
44     if(game_state_get_player(scene->gs, 1)->ctrl->type == CTRL_TYPE_AI) {
45         return 1;
46     }
47     return 0;
48 }
49 
spawn_position(int index,int scientist)50 vec2i spawn_position(int index, int scientist) {
51     switch (index) {
52         case 0:
53             // top left gantry
54             if (scientist) {
55                 return vec2i_create(90,80);
56             }
57             switch (rand_int(3)) {
58                 case 0:
59                     // middle
60                     return vec2i_create(90,80);
61                 case 1:
62                     // left arm
63                     return vec2i_create(30,80);
64                 case 2:
65                     // right arm
66                     return vec2i_create(120,80);
67             }
68             break;
69         case 1:
70             // top right gantry
71             if (scientist) {
72                 return vec2i_create(230,80);
73             }
74             switch (rand_int(3)) {
75                 case 0:
76                     // middle
77                     return vec2i_create(230,80);
78                 case 1:
79                     // left arm
80                     return vec2i_create(200,80);
81                 case 2:
82                     //right arm
83                     return vec2i_create(260,80);
84             }
85             break;
86         case 2:
87             // middle left gantry
88             return vec2i_create(90, 118);
89         case 3:
90             // middle right gantry
91             return vec2i_create(230,118);
92             //return vec2i_create(280,118);
93         // only welder can use the following
94         case 4:
95             // bottom left gantry
96             return vec2i_create(90,150);
97         case 5:
98             // bottom right gantry
99             return vec2i_create(230,150);
100         default:
101             break;
102     }
103     // default
104     return vec2i_create(160, 200);
105 }
106 
cb_vs_spawn_object(object * parent,int id,vec2i pos,int g,void * userdata)107 void cb_vs_spawn_object(object *parent, int id, vec2i pos, int g, void *userdata) {
108     scene *s = (scene*)userdata;
109 
110     // Get next animation
111     bk_info *info = bk_get_info(&s->bk_data, id);
112     if(info != NULL) {
113         object *obj = malloc(sizeof(object));
114         object_create(obj, parent->gs, vec2i_add(pos, vec2f_to_i(parent->pos)), vec2f_create(0,0));
115         object_set_stl(obj, object_get_stl(parent));
116         object_set_animation(obj, &info->ani);
117         object_set_spawn_cb(obj, cb_vs_spawn_object, userdata);
118         object_set_destroy_cb(obj, cb_vs_destroy_object, userdata);
119         game_state_add_object(parent->gs, obj, RENDER_LAYER_MIDDLE, 0, 0);
120     }
121 }
122 
cb_vs_destroy_object(object * parent,int id,void * userdata)123 void cb_vs_destroy_object(object *parent, int id, void *userdata) {
124     game_state_del_animation(parent->gs, id);
125 }
126 
vs_free(scene * scene)127 void vs_free(scene *scene) {
128     vs_local *local = scene_get_userdata(scene);
129     game_player *player2 = game_state_get_player(scene->gs, 1);
130 
131     dialog_free(&local->quit_dialog);
132     dialog_free(&local->too_pathetic_dialog);
133     surface_free(&local->arena_select_bg);
134     object_free(&local->player1_portrait);
135     object_free(&local->player2_portrait);
136     object_free(&local->player1_har);
137     object_free(&local->player2_har);
138     if (player2->selectable) {
139         object_free(&local->arena_select);
140     }
141     free(local);
142 }
143 
vs_handle_action(scene * scene,int action)144 void vs_handle_action(scene *scene, int action) {
145     vs_local *local = scene_get_userdata(scene);
146     if(dialog_is_visible(&local->too_pathetic_dialog)) {
147         dialog_event(&local->too_pathetic_dialog, action);
148     } else if(dialog_is_visible(&local->quit_dialog)) {
149         dialog_event(&local->quit_dialog, action);
150     } else {
151         switch (action) {
152             case ACT_KICK:
153             case ACT_PUNCH:
154                 game_state_set_next(scene->gs, SCENE_ARENA0+local->arena);
155                 break;
156             case ACT_UP:
157             case ACT_LEFT:
158                 if(game_state_get_player(scene->gs, 1)->selectable) {
159                     local->arena--;
160                     if (local->arena < 0) {
161                         local->arena =4;
162                     }
163                     object_select_sprite(&local->arena_select, local->arena);
164                 }
165                 break;
166             case ACT_DOWN:
167             case ACT_RIGHT:
168                 if(game_state_get_player(scene->gs, 1)->selectable) {
169                     local->arena++;
170                     if (local->arena > 4) {
171                         local->arena = 0;
172                     }
173                     object_select_sprite(&local->arena_select, local->arena);
174                 }
175                 break;
176         }
177     }
178 }
179 
vs_dynamic_tick(scene * scene,int paused)180 void vs_dynamic_tick(scene *scene, int paused) {
181     game_player *player1 = game_state_get_player(scene->gs, 0);
182     ctrl_event *i = NULL;
183     // Handle extra controller inputs
184     i = player1->ctrl->extra_events;
185     if (i) {
186         do {
187             if(i->type == EVENT_TYPE_ACTION) {
188                 vs_handle_action(scene, i->event_data.action);
189             } else if (i->type == EVENT_TYPE_CLOSE) {
190                 game_state_set_next(scene->gs, SCENE_MENU);
191                 return;
192             }
193         } while((i = i->next));
194     }
195 }
196 
vs_static_tick(scene * scene,int paused)197 void vs_static_tick(scene *scene, int paused) {
198     vs_local *local = scene->userdata;
199     if(dialog_is_visible(&local->too_pathetic_dialog)) {
200         dialog_tick(&local->too_pathetic_dialog);
201     } else if(dialog_is_visible(&local->quit_dialog)) {
202         dialog_tick(&local->quit_dialog);
203     }
204 }
205 
vs_input_tick(scene * scene)206 void vs_input_tick(scene *scene) {
207     vs_local *local = scene->userdata;
208     ctrl_event *p1=NULL, *i;
209     game_player *player1 = game_state_get_player(scene->gs, 0);
210     controller_poll(player1->ctrl, &p1);
211     i = p1;
212     if (i) {
213         do {
214             if(i->type == EVENT_TYPE_ACTION) {
215                 if (i->event_data.action == ACT_ESC) {
216                     if(dialog_is_visible(&local->too_pathetic_dialog)) {
217                         dialog_event(&local->too_pathetic_dialog, i->event_data.action);
218                     } else if(dialog_is_visible(&local->quit_dialog)) {
219                         dialog_event(&local->quit_dialog, i->event_data.action);
220                     } else if(vs_is_singleplayer(scene) && player1->sp_wins != 0) {
221                         // there's an active singleplayer campaign, confirm quitting
222                         dialog_show(&local->quit_dialog, 1);
223                     } else {
224                         game_state_set_next(scene->gs, SCENE_MELEE);
225                     }
226                 } else {
227                     vs_handle_action(scene, i->event_data.action);
228                 }
229             } else if (i->type == EVENT_TYPE_CLOSE) {
230                 game_state_set_next(scene->gs, SCENE_MENU);
231             }
232         } while((i = i->next));
233     }
234     controller_free_chain(p1);
235 }
236 
vs_render(scene * scene)237 void vs_render(scene *scene) {
238     vs_local *local = scene_get_userdata(scene);
239 
240     game_player *player1 = game_state_get_player(scene->gs, 0);
241     game_player *player2 = game_state_get_player(scene->gs, 1);
242 
243     // player 1 HAR
244     object_render(&local->player1_har);
245 
246     // player 2 HAR
247     object_render(&local->player2_har);
248 
249     // player 1 portrait
250     object_render(&local->player1_portrait);
251 
252     // player 2 portrait
253     object_render(&local->player2_portrait);
254 
255 
256     font_render_shadowed(&font_small, local->vs_str, 160-((strlen(local->vs_str)*font_small.w)/2), 3, COLOR_YELLOW, TEXT_SHADOW_RIGHT|TEXT_SHADOW_BOTTOM);
257 
258 
259     if (player2->selectable) {
260         // arena selection
261         video_render_sprite(&local->arena_select_bg, 55, 150, BLEND_ALPHA, 0);
262 
263         object_render(&local->arena_select);
264 
265         // arena name
266         font_render_wrapped(&font_small, lang_get(56+local->arena), 56+72, 153, (211-72)-4, COLOR_GREEN);
267 
268         // arena description
269         font_render_wrapped(&font_small, lang_get(66+local->arena), 56+72, 160, (211-72)-4, COLOR_GREEN);
270     } else if (player2->pilot_id == PILOT_KREISSACK && settings_get()->gameplay.difficulty < 2) {
271         // kriessack, but not on Veteran or higher
272         font_render_wrapped(&font_small, lang_get(747), 59, 160, 200, COLOR_YELLOW);
273     } else {
274         font_render_wrapped(&font_small, lang_get(749+(11*player1->pilot_id)+player2->pilot_id), 59, 160, 150, COLOR_YELLOW);
275         font_render_wrapped(&font_small, lang_get(870+(11*player2->pilot_id)+player1->pilot_id), 320-(59+150), 180, 150, COLOR_YELLOW);
276     }
277 }
278 
vs_render_overlay(scene * scene)279 void vs_render_overlay(scene *scene) {
280     vs_local *local = scene_get_userdata(scene);
281     if(dialog_is_visible(&local->quit_dialog)) {
282         dialog_render(&local->quit_dialog);
283     }
284 
285     if(dialog_is_visible(&local->too_pathetic_dialog)) {
286         dialog_render(&local->too_pathetic_dialog);
287     }
288 }
289 
vs_quit_dialog_clicked(dialog * dlg,dialog_result result)290 void vs_quit_dialog_clicked(dialog *dlg, dialog_result result){
291     scene *sc = dlg->userdata;
292     if(result == DIALOG_RESULT_YES_OK) {
293         game_state_set_next(sc->gs, SCENE_MELEE);
294     }
295 }
296 
vs_too_pathetic_dialog_clicked(dialog * dlg,dialog_result result)297 void vs_too_pathetic_dialog_clicked(dialog *dlg, dialog_result result){
298     scene *sc = dlg->userdata;
299     game_state_set_next(sc->gs, SCENE_MENU);
300 }
301 
vs_create(scene * scene)302 int vs_create(scene *scene) {
303     // Init local data
304     vs_local *local = malloc(sizeof(vs_local));
305     scene_set_userdata(scene, local);
306     game_player *player1 = game_state_get_player(scene->gs, 0);
307     game_player *player2 = game_state_get_player(scene->gs, 1);
308 
309     const char *pilot1 = lang_get(20+player1->pilot_id);
310     const char *pilot2 = lang_get(20+player2->pilot_id);
311     snprintf(local->vs_str, 128, "%*.*s VS. %*.*s",
312         (int)strlen(pilot1)-1, (int)strlen(pilot1)-1, pilot1,
313         (int)strlen(pilot2)-1, (int)strlen(pilot2)-1, pilot2);
314 
315     animation *ani;
316 
317     palette *mpal = video_get_base_palette();
318     palette_set_player_color(mpal, 0, player1->colors[2], 0);
319     palette_set_player_color(mpal, 0, player1->colors[1], 1);
320     palette_set_player_color(mpal, 0, player1->colors[0], 2);
321     palette_set_player_color(mpal, 1, player2->colors[2], 0);
322     palette_set_player_color(mpal, 1, player2->colors[1], 1);
323     palette_set_player_color(mpal, 1, player2->colors[0], 2);
324     video_force_pal_refresh();
325 
326     // HAR
327     ani = &bk_get_info(&scene->bk_data, 5)->ani;
328     object_create(&local->player1_har, scene->gs, vec2i_create(160,0), vec2f_create(0, 0));
329     object_set_animation(&local->player1_har, ani);
330     object_select_sprite(&local->player1_har, player1->har_id);
331 
332     object_create(&local->player2_har, scene->gs, vec2i_create(160,0), vec2f_create(0, 0));
333     object_set_animation(&local->player2_har, ani);
334     object_select_sprite(&local->player2_har, player2->har_id);
335     object_set_direction(&local->player2_har, OBJECT_FACE_LEFT);
336     object_set_pal_offset(&local->player2_har, 48);
337 
338     // PLAYER
339     ani = &bk_get_info(&scene->bk_data, 4)->ani;
340     object_create(&local->player1_portrait, scene->gs, vec2i_create(-10,150), vec2f_create(0, 0));
341     object_set_animation(&local->player1_portrait, ani);
342     object_select_sprite(&local->player1_portrait, player1->pilot_id);
343 
344     object_create(&local->player2_portrait, scene->gs, vec2i_create(330,150), vec2f_create(0, 0));
345     object_set_animation(&local->player2_portrait, ani);
346     object_select_sprite(&local->player2_portrait, player2->pilot_id);
347     object_set_direction(&local->player2_portrait, OBJECT_FACE_LEFT);
348 
349     // clone the left side of the background image
350     // Note! We are touching the scene-wide background surface!
351     surface_sub(&scene->bk_data.background, // DST Surface
352                 &scene->bk_data.background, // SRC Surface
353                 160, 0, // DST
354                 0, 0, // SRC
355                 160, 200, // Size
356                 SUB_METHOD_MIRROR); // Flip the right side horizontally
357 
358     if (player2->selectable) {
359         // player1 gets to choose, start at arena 0
360         local->arena = 0;
361     } else if (player2->pilot_id == PILOT_KREISSACK) {
362 	// force arena 0 when fighting Kreissack in 1 player mode
363 	local->arena = 0;
364     } else {
365         // pick a random arena for 1 player mode
366         local->arena = rand_int(5); // srand was done in melee
367     }
368 
369     // Arena
370     if(player2->selectable) {
371         ani = &bk_get_info(&scene->bk_data, 3)->ani;
372         object_create(&local->arena_select, scene->gs, vec2i_create(59,155), vec2f_create(0, 0));
373         object_set_animation(&local->arena_select, ani);
374         object_select_sprite(&local->arena_select, local->arena);
375     }
376 
377 
378     // SCIENTIST
379     int scientistpos = rand_int(4);
380     vec2i scientistcoord = spawn_position(scientistpos, 1);
381     if (scientistpos % 2) {
382         scientistcoord.x += 50;
383     } else {
384         scientistcoord.x -= 50;
385     }
386     object *o_scientist = malloc(sizeof(object));
387     ani = &bk_get_info(&scene->bk_data, 8)->ani;
388     object_create(o_scientist, scene->gs, scientistcoord, vec2f_create(0, 0));
389     object_set_animation(o_scientist, ani);
390     object_select_sprite(o_scientist, 0);
391     object_set_direction(o_scientist, scientistpos % 2 ? OBJECT_FACE_LEFT : OBJECT_FACE_RIGHT);
392     game_state_add_object(scene->gs, o_scientist, RENDER_LAYER_MIDDLE, 0, 0);
393 
394     // WELDER
395     int welderpos = rand_int(6);
396     // welder can't be on the same gantry or the same *side* as the scientist
397     // he also can't be on the same 'level'
398     // but he has 10 possible starting positions
399     while ((welderpos % 2)  == (scientistpos % 2) || (scientistpos < 2 && welderpos < 2) || (scientistpos > 1 && welderpos > 1 && welderpos < 4)) {
400         welderpos = rand_int(6);
401     }
402     object *o_welder = malloc(sizeof(object));
403     ani = &bk_get_info(&scene->bk_data, 7)->ani;
404     object_create(o_welder, scene->gs, spawn_position(welderpos, 0), vec2f_create(0, 0));
405     object_set_animation(o_welder, ani);
406     object_select_sprite(o_welder, 0);
407     object_set_spawn_cb(o_welder, cb_vs_spawn_object, (void*)scene);
408     object_set_destroy_cb(o_welder, cb_vs_destroy_object, (void*)scene);
409     object_set_direction(o_welder, welderpos % 2 ? OBJECT_FACE_LEFT : OBJECT_FACE_RIGHT);
410     game_state_add_object(scene->gs, o_welder, RENDER_LAYER_MIDDLE, 0, 0);
411 
412     // GANTRIES
413     object *o_gantry_a = malloc(sizeof(object));
414     ani = &bk_get_info(&scene->bk_data, 11)->ani;
415     object_create(o_gantry_a, scene->gs, vec2i_create(0,0), vec2f_create(0, 0));
416     object_set_animation(o_gantry_a, ani);
417     object_select_sprite(o_gantry_a, 0);
418     game_state_add_object(scene->gs, o_gantry_a, RENDER_LAYER_TOP, 0, 0);
419 
420     object *o_gantry_b = malloc(sizeof(object));
421     object_create(o_gantry_b, scene->gs, vec2i_create(320,0), vec2f_create(0, 0));
422     object_set_animation(o_gantry_b, ani);
423     object_select_sprite(o_gantry_b, 0);
424     object_set_direction(o_gantry_b, OBJECT_FACE_LEFT);
425     game_state_add_object(scene->gs, o_gantry_b, RENDER_LAYER_TOP, 0, 0);
426 
427     // Background tex
428     menu_background2_create(&local->arena_select_bg, 211, 50);
429 
430     // Quit Dialog
431     dialog_create(&local->quit_dialog, DIALOG_STYLE_YES_NO, "ARE YOU SURE YOU WANT TO QUIT THIS GAME?", 72, 60);
432     local->quit_dialog.userdata = scene;
433     local->quit_dialog.clicked = vs_quit_dialog_clicked;
434 
435     // Too Pathetic Dialog
436     char insult[512];
437     snprintf(insult, 512, lang_get(748), "Veteran", "Major Kreissack");
438     dialog_create(&local->too_pathetic_dialog, DIALOG_STYLE_OK, insult, 72, 60);
439     local->too_pathetic_dialog.userdata = scene;
440     local->too_pathetic_dialog.clicked = vs_too_pathetic_dialog_clicked;
441 
442     if (player2->pilot_id == PILOT_KREISSACK && settings_get()->gameplay.difficulty < 2) {
443         // kriessack, but not on Veteran or higher
444         dialog_show(&local->too_pathetic_dialog, 1);
445     }
446 
447     // Callbacks
448     scene_set_render_cb(scene, vs_render);
449     scene_set_render_overlay_cb(scene, vs_render_overlay);
450     scene_set_input_poll_cb(scene, vs_input_tick);
451     scene_set_dynamic_tick_cb(scene, vs_dynamic_tick);
452     scene_set_static_tick_cb(scene, vs_static_tick);
453     scene_set_free_cb(scene, vs_free);
454 
455     // Pick renderer
456     video_select_renderer(VIDEO_RENDERER_HW);
457 
458     return 0;
459 }
460