1 /*
2 * OpenTyrian: A modern cross-platform port of Tyrian
3 * Copyright (C) 2007-2009 The OpenTyrian Development Team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19 #include "backgrnd.h"
20 #include "config.h"
21 #include "editship.h"
22 #include "episodes.h"
23 #include "file.h"
24 #include "fonthand.h"
25 #include "helptext.h"
26 #include "helptext.h"
27 #include "joystick.h"
28 #include "keyboard.h"
29 #include "lds_play.h"
30 #include "loudness.h"
31 #include "mainint.h"
32 #include "menus.h"
33 #include "mouse.h"
34 #include "mtrand.h"
35 #include "network.h"
36 #include "nortsong.h"
37 #include "nortvars.h"
38 #include "opentyr.h"
39 #include "palette.h"
40 #include "params.h"
41 #include "pcxmast.h"
42 #include "picload.h"
43 #include "player.h"
44 #include "setup.h"
45 #include "shots.h"
46 #include "sndmast.h"
47 #include "sprite.h"
48 #include "varz.h"
49 #include "vga256d.h"
50 #include "video.h"
51
52 #include <assert.h>
53 #include <ctype.h>
54
55 bool button[4];
56
57 #define MAX_PAGE 8
58 #define TOPICS 6
59 const JE_byte topicStart[TOPICS] = { 0, 1, 2, 3, 7, 255 };
60
61 JE_shortint constantLastX;
62 JE_word textErase;
63 JE_word upgradeCost;
64 JE_word downgradeCost;
65 JE_boolean performSave;
66 JE_boolean jumpSection;
67 JE_boolean useLastBank; /* See if I want to use the last 16 colors for DisplayText */
68
69 bool pause_pressed = false, ingamemenu_pressed = false;
70
71 /* Draws a message at the bottom text window on the playing screen */
JE_drawTextWindow(const char * text)72 void JE_drawTextWindow( const char *text )
73 {
74 if (textErase > 0) // erase current text
75 blit_sprite(VGAScreenSeg, 16, 189, OPTION_SHAPES, 36); // in-game text area
76
77 textErase = 100;
78 JE_outText(VGAScreenSeg, 20, 190, text, 0, 4);
79 }
80
JE_outCharGlow(JE_word x,JE_word y,const char * s)81 void JE_outCharGlow( JE_word x, JE_word y, const char *s )
82 {
83 JE_integer maxloc, loc, z;
84 JE_shortint glowcol[60]; /* [1..60] */
85 JE_shortint glowcolc[60]; /* [1..60] */
86 JE_word textloc[60]; /* [1..60] */
87 JE_byte bank;
88
89 setjasondelay2(1);
90
91 bank = (warningRed) ? 7 : ((useLastBank) ? 15 : 14);
92
93 if (s[0] == '\0')
94 return;
95
96 if (frameCountMax == 0)
97 {
98 JE_textShade(VGAScreen, x, y, s, bank, 0, PART_SHADE);
99 JE_showVGA();
100 }
101 else
102 {
103 maxloc = strlen(s);
104 for (z = 0; z < 60; z++)
105 {
106 glowcol[z] = -8;
107 glowcolc[z] = 1;
108 }
109
110 loc = x;
111 for (z = 0; z < maxloc; z++)
112 {
113 textloc[z] = loc;
114
115 int sprite_id = font_ascii[(unsigned char)s[z]];
116
117 if (s[z] == ' ')
118 loc += 6;
119 else if (sprite_id != -1)
120 loc += sprite(TINY_FONT, sprite_id)->width + 1;
121 }
122
123 for (loc = 0; (unsigned)loc < strlen(s) + 28; loc++)
124 {
125 if (!ESCPressed)
126 {
127 setjasondelay(frameCountMax);
128
129 NETWORK_KEEP_ALIVE();
130
131 int sprite_id = -1;
132
133 for (z = loc - 28; z <= loc; z++)
134 {
135 if (z >= 0 && z < maxloc)
136 {
137 sprite_id = font_ascii[(unsigned char)s[z]];
138
139 if (sprite_id != -1)
140 {
141 blit_sprite_hv(VGAScreen, textloc[z], y, TINY_FONT, sprite_id, bank, glowcol[z]);
142
143 glowcol[z] += glowcolc[z];
144 if (glowcol[z] > 9)
145 glowcolc[z] = -1;
146 }
147 }
148 }
149 if (sprite_id != -1 && --z < maxloc)
150 blit_sprite_dark(VGAScreen, textloc[z] + 1, y + 1, TINY_FONT, sprite_id, true);
151
152 if (JE_anyButton())
153 frameCountMax = 0;
154
155 do
156 {
157 if (levelWarningDisplay)
158 JE_updateWarning(VGAScreen);
159
160 SDL_Delay(16);
161 }
162 while (!(delaycount() == 0 || ESCPressed));
163
164 JE_showVGA();
165 }
166 }
167 }
168 }
169
JE_drawPortConfigButtons(void)170 void JE_drawPortConfigButtons( void ) // rear weapon pattern indicator
171 {
172 if (twoPlayerMode)
173 return;
174
175 if (player[0].weapon_mode == 1)
176 {
177 blit_sprite(VGAScreenSeg, 285, 44, OPTION_SHAPES, 18); // lit
178 blit_sprite(VGAScreenSeg, 302, 44, OPTION_SHAPES, 19); // unlit
179 }
180 else // == 2
181 {
182 blit_sprite(VGAScreenSeg, 285, 44, OPTION_SHAPES, 19); // unlit
183 blit_sprite(VGAScreenSeg, 302, 44, OPTION_SHAPES, 18); // lit
184 }
185 }
186
JE_helpSystem(JE_byte startTopic)187 void JE_helpSystem( JE_byte startTopic )
188 {
189 JE_integer page, lastPage = 0;
190 JE_byte menu;
191
192 page = topicStart[startTopic-1];
193
194 fade_black(10);
195 JE_loadPic(VGAScreen, 2, false);
196
197 play_song(SONG_MAPVIEW);
198
199 JE_showVGA();
200 fade_palette(colors, 10, 0, 255);
201
202 memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
203
204 do
205 {
206 memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
207
208 temp2 = 0;
209
210 for (temp = 0; temp < TOPICS; temp++)
211 {
212 if (topicStart[temp] <= page)
213 {
214 temp2 = temp;
215 }
216 }
217
218 if (page > 0)
219 {
220 JE_char buf[128];
221
222 sprintf(buf, "%s %d", miscText[24], page-topicStart[temp2]+1);
223 JE_outText(VGAScreen, 10, 192, buf, 13, 5);
224
225 sprintf(buf, "%s %d of %d", miscText[25], page, MAX_PAGE);
226 JE_outText(VGAScreen, 220, 192, buf, 13, 5);
227
228 JE_dString(VGAScreen, JE_fontCenter(topicName[temp2], SMALL_FONT_SHAPES), 1, topicName[temp2], SMALL_FONT_SHAPES);
229 }
230
231 menu = 0;
232
233 helpBoxBrightness = 3;
234 verticalHeight = 8;
235
236 switch (page)
237 {
238 case 0:
239 menu = 2;
240 if (lastPage == MAX_PAGE)
241 {
242 menu = TOPICS;
243 }
244 JE_dString(VGAScreen, JE_fontCenter(topicName[0], FONT_SHAPES), 30, topicName[0], FONT_SHAPES);
245
246 do
247 {
248 for (temp = 1; temp <= TOPICS; temp++)
249 {
250 char buf[21+1];
251
252 if (temp == menu-1)
253 {
254 strcpy(buf+1, topicName[temp]);
255 buf[0] = '~';
256 } else {
257 strcpy(buf, topicName[temp]);
258 }
259
260 JE_dString(VGAScreen, JE_fontCenter(topicName[temp], SMALL_FONT_SHAPES), temp * 20 + 40, buf, SMALL_FONT_SHAPES);
261 }
262
263 //JE_waitRetrace(); didn't do anything anyway?
264 JE_showVGA();
265
266 tempW = 0;
267 JE_textMenuWait(&tempW, false);
268 if (newkey)
269 {
270 switch (lastkey_sym)
271 {
272 case SDLK_UP:
273 menu--;
274 if (menu < 2)
275 {
276 menu = TOPICS;
277 }
278 JE_playSampleNum(S_CURSOR);
279 break;
280 case SDLK_DOWN:
281 menu++;
282 if (menu > TOPICS)
283 {
284 menu = 2;
285 }
286 JE_playSampleNum(S_CURSOR);
287 break;
288 default:
289 break;
290 }
291 }
292 } while (!(lastkey_sym == SDLK_ESCAPE || lastkey_sym == SDLK_RETURN));
293
294 if (lastkey_sym == SDLK_RETURN)
295 {
296 page = topicStart[menu-1];
297 JE_playSampleNum(S_CLICK);
298 }
299
300 break;
301 case 1: /* One-Player Menu */
302 JE_HBox(VGAScreen, 10, 20, 2, 60);
303 JE_HBox(VGAScreen, 10, 50, 5, 60);
304 JE_HBox(VGAScreen, 10, 80, 21, 60);
305 JE_HBox(VGAScreen, 10, 110, 1, 60);
306 JE_HBox(VGAScreen, 10, 140, 28, 60);
307 break;
308 case 2: /* Two-Player Menu */
309 JE_HBox(VGAScreen, 10, 20, 1, 60);
310 JE_HBox(VGAScreen, 10, 60, 2, 60);
311 JE_HBox(VGAScreen, 10, 100, 21, 60);
312 JE_HBox(VGAScreen, 10, 140, 28, 60);
313 break;
314 case 3: /* Upgrade Ship */
315 JE_HBox(VGAScreen, 10, 20, 5, 60);
316 JE_HBox(VGAScreen, 10, 70, 6, 60);
317 JE_HBox(VGAScreen, 10, 110, 7, 60);
318 break;
319 case 4:
320 JE_HBox(VGAScreen, 10, 20, 8, 60);
321 JE_HBox(VGAScreen, 10, 55, 9, 60);
322 JE_HBox(VGAScreen, 10, 87, 10, 60);
323 JE_HBox(VGAScreen, 10, 120, 11, 60);
324 JE_HBox(VGAScreen, 10, 170, 13, 60);
325 break;
326 case 5:
327 JE_HBox(VGAScreen, 10, 20, 14, 60);
328 JE_HBox(VGAScreen, 10, 80, 15, 60);
329 JE_HBox(VGAScreen, 10, 120, 16, 60);
330 break;
331 case 6:
332 JE_HBox(VGAScreen, 10, 20, 17, 60);
333 JE_HBox(VGAScreen, 10, 40, 18, 60);
334 JE_HBox(VGAScreen, 10, 130, 20, 60);
335 break;
336 case 7: /* Options */
337 JE_HBox(VGAScreen, 10, 20, 21, 60);
338 JE_HBox(VGAScreen, 10, 70, 22, 60);
339 JE_HBox(VGAScreen, 10, 110, 23, 60);
340 JE_HBox(VGAScreen, 10, 140, 24, 60);
341 break;
342 case 8:
343 JE_HBox(VGAScreen, 10, 20, 25, 60);
344 JE_HBox(VGAScreen, 10, 60, 26, 60);
345 JE_HBox(VGAScreen, 10, 100, 27, 60);
346 JE_HBox(VGAScreen, 10, 140, 28, 60);
347 JE_HBox(VGAScreen, 10, 170, 29, 60);
348 break;
349 }
350
351 helpBoxBrightness = 1;
352 verticalHeight = 7;
353
354 lastPage = page;
355
356 if (menu == 0)
357 {
358 do {
359 setjasondelay(3);
360
361 push_joysticks_as_keyboard();
362 service_SDL_events(true);
363
364 JE_showVGA();
365
366 wait_delay();
367 } while (!newkey && !newmouse);
368
369 wait_noinput(false, true, false);
370
371 if (newmouse)
372 {
373 switch (lastmouse_but)
374 {
375 case SDL_BUTTON_LEFT:
376 lastkey_sym = SDLK_RIGHT;
377 break;
378 case SDL_BUTTON_RIGHT:
379 lastkey_sym = SDLK_LEFT;
380 break;
381 case SDL_BUTTON_MIDDLE:
382 lastkey_sym = SDLK_ESCAPE;
383 break;
384 }
385 do
386 {
387 service_SDL_events(false);
388 } while (mousedown);
389 newkey = true;
390 }
391
392 if (newkey)
393 {
394 switch (lastkey_sym)
395 {
396 case SDLK_LEFT:
397 case SDLK_UP:
398 case SDLK_PAGEUP:
399 page--;
400 JE_playSampleNum(S_CURSOR);
401 break;
402 case SDLK_RIGHT:
403 case SDLK_DOWN:
404 case SDLK_PAGEDOWN:
405 case SDLK_RETURN:
406 case SDLK_SPACE:
407 if (page == MAX_PAGE)
408 {
409 page = 0;
410 } else {
411 page++;
412 }
413 JE_playSampleNum(S_CURSOR);
414 break;
415 case SDLK_F1:
416 page = 0;
417 JE_playSampleNum(S_CURSOR);
418 break;
419 default:
420 break;
421 }
422 }
423 }
424
425 if (page == 255)
426 {
427 lastkey_sym = SDLK_ESCAPE;
428 }
429 } while (lastkey_sym != SDLK_ESCAPE);
430 }
431
432 // cost to upgrade a weapon power from power-1 (where power == 0 indicates an unupgraded weapon)
weapon_upgrade_cost(long base_cost,unsigned int power)433 long weapon_upgrade_cost( long base_cost, unsigned int power )
434 {
435 assert(power <= 11);
436
437 unsigned int temp = 0;
438
439 // 0 1 3 6 10 15 21 29 ...
440 for (; power > 0; power--)
441 temp += power;
442
443 return base_cost * temp;
444 }
445
JE_getCost(JE_byte itemType,JE_word itemNum)446 ulong JE_getCost( JE_byte itemType, JE_word itemNum )
447 {
448 long cost = 0;
449
450 switch (itemType)
451 {
452 case 2:
453 cost = (itemNum > 90) ? 100 : ships[itemNum].cost;
454 break;
455 case 3:
456 case 4:
457 cost = weaponPort[itemNum].cost;
458
459 const uint port = itemType - 3,
460 item_power = player[0].items.weapon[port].power - 1;
461
462 downgradeCost = weapon_upgrade_cost(cost, item_power);
463 upgradeCost = weapon_upgrade_cost(cost, item_power + 1);
464 break;
465 case 5:
466 cost = shields[itemNum].cost;
467 break;
468 case 6:
469 cost = powerSys[itemNum].cost;
470 break;
471 case 7:
472 case 8:
473 cost = options[itemNum].cost;
474 break;
475 }
476
477 return cost;
478 }
479
JE_loadScreen(void)480 void JE_loadScreen( void )
481 {
482 JE_boolean quit;
483 JE_byte sel, screen, min = 0, max = 0;
484 char *tempstr;
485 char *tempstr2;
486 JE_boolean mal_str = false;
487 int len;
488
489 tempstr = NULL;
490
491 free_sprite2s(&shapes6);
492 JE_loadCompShapes(&shapes6, '1'); // need arrow sprites
493
494 fade_black(10);
495 JE_loadPic(VGAScreen, 2, false);
496 JE_showVGA();
497 fade_palette(colors, 10, 0, 255);
498
499 screen = 1;
500 sel = 1;
501 quit = false;
502
503 memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
504
505 do
506 {
507 while (mousedown)
508 {
509 service_SDL_events(false);
510 tempX = mouse_x;
511 tempY = mouse_y;
512 }
513
514 memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
515
516 JE_dString(VGAScreen, JE_fontCenter(miscText[38 + screen - 1], FONT_SHAPES), 5, miscText[38 + screen - 1], FONT_SHAPES);
517
518 switch (screen)
519 {
520 case 1:
521 min = 1;
522 max = 12;
523 break;
524 case 2:
525 min = 12;
526 max = 23;
527 }
528
529 /* SYN: Go through text line by line */
530 for (x = min; x <= max; x++)
531 {
532 tempY = 30 + (x - min) * 13;
533
534 if (x == max)
535 {
536 /* Last line is return to main menu, not a save game */
537 if (mal_str)
538 {
539 free(tempstr);
540 mal_str = false;
541 }
542 tempstr = miscText[34 - 1];
543
544 if (x == sel) /* Highlight if selected */
545 {
546 temp2 = 254;
547 } else {
548 temp2 = 250;
549 }
550 } else {
551 if (x == sel) /* Highlight if selected */
552 {
553 temp2 = 254;
554 } else {
555 temp2 = 250 - ((saveFiles[x - 1].level == 0) << 1);
556 }
557
558 if (saveFiles[x - 1].level == 0) /* I think this means the save file is unused */
559 {
560 if (mal_str)
561 {
562 free(tempstr);
563 mal_str = false;
564 }
565 tempstr = miscText[3 - 1];
566 } else {
567 if (mal_str)
568 {
569 free(tempstr);
570 mal_str = false;
571 }
572 tempstr = saveFiles[x - 1].name;
573 }
574 }
575
576 /* Write first column text */
577 JE_textShade(VGAScreen, 10, tempY, tempstr, 13, (temp2 % 16) - 8, FULL_SHADE);
578
579 if (x < max) /* Write additional columns for all but the last row */
580 {
581 if (saveFiles[x - 1].level == 0)
582 {
583 if (mal_str)
584 {
585 free(tempstr);
586 }
587 tempstr = malloc(7);
588 mal_str = true;
589 strcpy(tempstr, "-----"); /* Unused save slot */
590 } else {
591 tempstr = saveFiles[x - 1].levelName;
592 tempstr2 = malloc(5 + strlen(miscTextB[2-1]));
593 sprintf(tempstr2, "%s %d", miscTextB[2-1], saveFiles[x - 1].episode);
594 JE_textShade(VGAScreen, 250, tempY, tempstr2, 5, (temp2 % 16) - 8, FULL_SHADE);
595 free(tempstr2);
596 }
597
598 len = strlen(miscTextB[3-1]) + 2 + strlen(tempstr);
599 tempstr2 = malloc(len);
600 sprintf(tempstr2, "%s %s", miscTextB[3 - 1], tempstr);
601 JE_textShade(VGAScreen, 120, tempY, tempstr2, 5, (temp2 % 16) - 8, FULL_SHADE);
602 free(tempstr2);
603 }
604
605 }
606
607 if (screen == 2)
608 {
609 blit_sprite2x2(VGAScreen, 90, 180, shapes6, 279);
610 }
611 if (screen == 1)
612 {
613 blit_sprite2x2(VGAScreen, 220, 180, shapes6, 281);
614 }
615
616 helpBoxColor = 15;
617 JE_helpBox(VGAScreen, 110, 182, miscText[56-1], 25);
618
619 JE_showVGA();
620
621 tempW = 0;
622 JE_textMenuWait(&tempW, false);
623
624
625 if (newkey)
626 {
627 switch (lastkey_sym)
628 {
629 case SDLK_UP:
630 sel--;
631 if (sel < min)
632 {
633 sel = max;
634 }
635 JE_playSampleNum(S_CURSOR);
636 break;
637 case SDLK_DOWN:
638 sel++;
639 if (sel > max)
640 {
641 sel = min;
642 }
643 JE_playSampleNum(S_CURSOR);
644 break;
645 case SDLK_LEFT:
646 case SDLK_RIGHT:
647 if (screen == 1)
648 {
649 screen = 2;
650 sel += 11;
651 } else {
652 screen = 1;
653 sel -= 11;
654 }
655 break;
656 case SDLK_RETURN:
657 if (sel < max)
658 {
659 if (saveFiles[sel - 1].level > 0)
660 {
661 JE_playSampleNum (S_SELECT);
662 performSave = false;
663 JE_operation(sel);
664 quit = true;
665 } else {
666 JE_playSampleNum (S_CLINK);
667 }
668 } else {
669 quit = true;
670 }
671
672
673 break;
674 case SDLK_ESCAPE:
675 quit = true;
676 break;
677 default:
678 break;
679 }
680
681 }
682 } while (!quit);
683 }
684
JE_totalScore(const Player * this_player)685 ulong JE_totalScore( const Player *this_player )
686 {
687 ulong temp = this_player->cash;
688
689 temp += JE_getValue(2, this_player->items.ship);
690 temp += JE_getValue(3, this_player->items.weapon[FRONT_WEAPON].id);
691 temp += JE_getValue(4, this_player->items.weapon[REAR_WEAPON].id);
692 temp += JE_getValue(5, this_player->items.shield);
693 temp += JE_getValue(6, this_player->items.generator);
694 temp += JE_getValue(7, this_player->items.sidekick[LEFT_SIDEKICK]);
695 temp += JE_getValue(8, this_player->items.sidekick[RIGHT_SIDEKICK]);
696
697 return temp;
698 }
699
JE_getValue(JE_byte itemType,JE_word itemNum)700 JE_longint JE_getValue( JE_byte itemType, JE_word itemNum )
701 {
702 long value = 0;
703
704 switch (itemType)
705 {
706 case 2:
707 value = ships[itemNum].cost;
708 break;
709 case 3:
710 case 4:;
711 const long base_value = weaponPort[itemNum].cost;
712
713 // if two-player, use first player's front and second player's rear weapon
714 const uint port = itemType - 3;
715 const uint item_power = player[twoPlayerMode ? port : 0].items.weapon[port].power - 1;
716
717 value = base_value;
718 for (unsigned int i = 1; i <= item_power; ++i)
719 value += weapon_upgrade_cost(base_value, i);
720 break;
721 case 5:
722 value = shields[itemNum].cost;
723 break;
724 case 6:
725 value = powerSys[itemNum].cost;
726 break;
727 case 7:
728 case 8:
729 value = options[itemNum].cost;
730 break;
731 }
732
733 return value;
734 }
735
JE_nextEpisode(void)736 void JE_nextEpisode( void )
737 {
738 strcpy(lastLevelName, "Completed");
739
740 if (episodeNum == initial_episode_num && !gameHasRepeated && episodeNum != EPISODE_AVAILABLE &&
741 !isNetworkGame && !constantPlay)
742 {
743 JE_highScoreCheck();
744 }
745
746 unsigned int newEpisode = JE_findNextEpisode();
747
748 if (jumpBackToEpisode1)
749 {
750 // shareware version check
751 if (episodeNum == 1 &&
752 !isNetworkGame && !constantPlay)
753 {
754 // JE_loadOrderingInfo();
755 }
756
757 if (episodeNum > 2 &&
758 !constantPlay)
759 {
760 JE_playCredits();
761 }
762
763 // randomly give player the SuperCarrot
764 if ((mt_rand() % 6) == 0)
765 {
766 player[0].items.ship = 2; // SuperCarrot
767 player[0].items.weapon[FRONT_WEAPON].id = 23; // Banana Blast
768 player[0].items.weapon[REAR_WEAPON].id = 24; // Banana Blast Rear
769
770 for (uint i = 0; i < COUNTOF(player[0].items.weapon); ++i)
771 player[0].items.weapon[i].power = 1;
772
773 player[1].items.weapon[REAR_WEAPON].id = 24; // Banana Blast Rear
774
775 player[0].last_items = player[0].items;
776 }
777 }
778
779 if (newEpisode != episodeNum)
780 JE_initEpisode(newEpisode);
781
782 gameLoaded = true;
783 mainLevel = FIRST_LEVEL;
784 saveLevel = FIRST_LEVEL;
785
786 play_song(26);
787
788 JE_clr256(VGAScreen);
789 memcpy(colors, palettes[6-1], sizeof(colors));
790
791 JE_dString(VGAScreen, JE_fontCenter(episode_name[episodeNum], SMALL_FONT_SHAPES), 130, episode_name[episodeNum], SMALL_FONT_SHAPES);
792 JE_dString(VGAScreen, JE_fontCenter(miscText[5-1], SMALL_FONT_SHAPES), 185, miscText[5-1], SMALL_FONT_SHAPES);
793
794 JE_showVGA();
795 fade_palette(colors, 15, 0, 255);
796
797 JE_wipeKey();
798 if (!constantPlay)
799 {
800 do
801 {
802 NETWORK_KEEP_ALIVE();
803
804 SDL_Delay(16);
805 } while (!JE_anyButton());
806 }
807
808 fade_black(15);
809 }
810
JE_initPlayerData(void)811 void JE_initPlayerData( void )
812 {
813 /* JE: New Game Items/Data */
814
815 player[0].items.ship = 1; // USP Talon
816 player[0].items.weapon[FRONT_WEAPON].id = 1; // Pulse Cannon
817 player[0].items.weapon[REAR_WEAPON].id = 0; // None
818 player[0].items.shield = 4; // Gencore High Energy Shield
819 player[0].items.generator = 2; // Advanced MR-12
820 for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i)
821 player[0].items.sidekick[i] = 0; // None
822 player[0].items.special = 0; // None
823
824 player[0].last_items = player[0].items;
825
826 player[1].items = player[0].items;
827 player[1].items.weapon[REAR_WEAPON].id = 15; // Vulcan Cannon
828 player[1].items.sidekick_level = 101; // 101, 102, 103
829 player[1].items.sidekick_series = 0; // None
830
831 gameHasRepeated = false;
832 onePlayerAction = false;
833 superArcadeMode = SA_NONE;
834 superTyrian = false;
835 twoPlayerMode = false;
836
837 secretHint = (mt_rand() % 3) + 1;
838
839 for (uint p = 0; p < COUNTOF(player); ++p)
840 {
841 for (uint i = 0; i < COUNTOF(player->items.weapon); ++i)
842 {
843 player[p].items.weapon[i].power = 1;
844 }
845
846 player[p].weapon_mode = 1;
847 player[p].armor = ships[player[p].items.ship].dmg;
848
849 player[p].is_dragonwing = (p == 1);
850 player[p].lives = &player[p].items.weapon[p].power;
851
852 }
853
854 mainLevel = FIRST_LEVEL;
855 saveLevel = FIRST_LEVEL;
856
857 strcpy(lastLevelName, miscText[19]);
858 }
859
JE_sortHighScores(void)860 void JE_sortHighScores( void )
861 {
862 JE_byte x;
863
864 temp = 0;
865 for (x = 0; x < 6; x++)
866 {
867 JE_sort();
868 temp += 3;
869 }
870 }
871
JE_highScoreScreen(void)872 void JE_highScoreScreen( void )
873 {
874 int min = 1;
875 int max = 3;
876
877 int x, z;
878 short int chg;
879 int quit;
880 char scoretemp[32];
881
882 free_sprite2s(&shapes6);
883 JE_loadCompShapes(&shapes6, '1'); // need arrow sprites
884
885 fade_black(10);
886 JE_loadPic(VGAScreen, 2, false);
887 JE_showVGA();
888 fade_palette(colors, 10, 0, 255);
889
890 quit = false;
891 x = 1;
892 chg = 1;
893
894 memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
895
896 do
897 {
898 if (episodeAvail[x-1])
899 {
900 memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
901
902 JE_dString(VGAScreen, JE_fontCenter(miscText[51 - 1], FONT_SHAPES), 03, miscText[51 - 1], FONT_SHAPES);
903 JE_dString(VGAScreen, JE_fontCenter(episode_name[x], SMALL_FONT_SHAPES), 30, episode_name[x], SMALL_FONT_SHAPES);
904
905 /* Player 1 */
906 temp = (x * 6) - 6;
907
908 JE_dString(VGAScreen, JE_fontCenter(miscText[47 - 1], SMALL_FONT_SHAPES), 55, miscText[47 - 1], SMALL_FONT_SHAPES);
909
910 for (z = 0; z < 3; z++)
911 {
912 int difficulty = saveFiles[temp + z].highScoreDiff;
913 if (difficulty > 9)
914 {
915 saveFiles[temp + z].highScoreDiff = 0;
916 difficulty = 0;
917 }
918 sprintf(scoretemp, "~#%d:~ %d", z + 1, saveFiles[temp+z].highScore1);
919 JE_textShade(VGAScreen, 250, ((z+1) * 10) + 65 , difficultyNameB[difficulty], 15, difficulty + (difficulty == 0 ? 0 : -1), FULL_SHADE);
920 JE_textShade(VGAScreen, 20, ((z+1) * 10) + 65 , scoretemp, 15, 0, FULL_SHADE);
921 JE_textShade(VGAScreen, 110, ((z+1) * 10) + 65 , saveFiles[temp + z].highScoreName, 15, 2, FULL_SHADE);
922 }
923
924 /* Player 2 */
925 temp += 3;
926
927 JE_dString(VGAScreen, JE_fontCenter( miscText[48 - 1], SMALL_FONT_SHAPES), 120, miscText[48 - 1], SMALL_FONT_SHAPES);
928
929 /*{ textshade(20,125,misctext[49],15,3,_FullShade);
930 textshade(80,125,misctext[50],15,3,_FullShade);}*/
931
932 for (z = 0; z < 3; z++)
933 {
934 int difficulty = saveFiles[temp + z].highScoreDiff;
935 if (difficulty > 9)
936 {
937 saveFiles[temp + z].highScoreDiff = 0;
938 difficulty = 0;
939 }
940 sprintf(scoretemp, "~#%d:~ %d", z + 1, saveFiles[temp+z].highScore1); /* Not .highScore2 for some reason */
941 JE_textShade(VGAScreen, 250, ((z+1) * 10) + 125 , difficultyNameB[difficulty], 15, difficulty + (difficulty == 0 ? 0 : -1), FULL_SHADE);
942 JE_textShade(VGAScreen, 20, ((z+1) * 10) + 125 , scoretemp, 15, 0, FULL_SHADE);
943 JE_textShade(VGAScreen, 110, ((z+1) * 10) + 125 , saveFiles[temp + z].highScoreName, 15, 2, FULL_SHADE);
944 }
945
946 if (x > 1)
947 {
948 blit_sprite2x2(VGAScreen, 90, 180, shapes6, 279);
949 }
950
951 if ( ( (x < 2) && episodeAvail[2-1] ) || ( (x < 3) && episodeAvail[3-1] ) )
952 {
953 blit_sprite2x2(VGAScreen, 220, 180, shapes6, 281);
954 }
955
956 helpBoxColor = 15;
957 JE_helpBox(VGAScreen, 110, 182, miscText[57 - 1], 25);
958
959 /* {Dstring(fontcenter(misctext[57],_SmallFontShapes),190,misctext[57],_SmallFontShapes);} */
960
961 JE_showVGA();
962
963 tempW = 0;
964 JE_textMenuWait(&tempW, false);
965
966 if (newkey)
967 {
968 switch (lastkey_sym)
969 {
970 case SDLK_LEFT:
971 x--;
972 chg = -1;
973 break;
974 case SDLK_RIGHT:
975 x++;
976 chg = 1;
977 break;
978 default:
979 break;
980 }
981 }
982
983 } else {
984 x += chg;
985 }
986
987 x = ( x < min ) ? max : ( x > max ) ? min : x;
988
989 if (newkey)
990 {
991 switch (lastkey_sym)
992 {
993 case SDLK_RETURN:
994 case SDLK_ESCAPE:
995 quit = true;
996 break;
997 default:
998 break;
999 }
1000 }
1001
1002 } while (!quit);
1003
1004 }
1005
JE_gammaCorrect_func(JE_byte * col,JE_real r)1006 void JE_gammaCorrect_func( JE_byte *col, JE_real r )
1007 {
1008 int temp = roundf(*col * r);
1009 if (temp > 255)
1010 {
1011 temp = 255;
1012 }
1013 *col = temp;
1014 }
1015
JE_gammaCorrect(Palette * colorBuffer,JE_byte gamma)1016 void JE_gammaCorrect( Palette *colorBuffer, JE_byte gamma )
1017 {
1018 int x;
1019 JE_real r = 1 + (JE_real)gamma / 10;
1020
1021 for (x = 0; x < 256; x++)
1022 {
1023 JE_gammaCorrect_func(&(*colorBuffer)[x].r, r);
1024 JE_gammaCorrect_func(&(*colorBuffer)[x].g, r);
1025 JE_gammaCorrect_func(&(*colorBuffer)[x].b, r);
1026 }
1027 }
1028
JE_gammaCheck(void)1029 JE_boolean JE_gammaCheck( void )
1030 {
1031 bool temp = keysactive[SDLK_F11] != 0;
1032 if (temp)
1033 {
1034 keysactive[SDLK_F11] = false;
1035 newkey = false;
1036 gammaCorrection = (gammaCorrection + 1) % 4;
1037 memcpy(colors, palettes[pcxpal[3-1]], sizeof(colors));
1038 JE_gammaCorrect(&colors, gammaCorrection);
1039 set_palette(colors, 0, 255);
1040 }
1041 return temp;
1042 }
1043
JE_doInGameSetup(void)1044 void JE_doInGameSetup( void )
1045 {
1046 haltGame = false;
1047
1048 #ifdef WITH_NETWORK
1049 if (isNetworkGame)
1050 {
1051 network_prepare(PACKET_GAME_MENU);
1052 network_send(4); // PACKET_GAME_MENU
1053
1054 while (true)
1055 {
1056 service_SDL_events(false);
1057
1058 if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_GAME_MENU)
1059 {
1060 network_update();
1061 break;
1062 }
1063
1064 network_update();
1065 network_check();
1066
1067 SDL_Delay(16);
1068 }
1069 }
1070 #endif
1071
1072 if (yourInGameMenuRequest)
1073 {
1074 if (JE_inGameSetup())
1075 {
1076 reallyEndLevel = true;
1077 playerEndLevel = true;
1078 }
1079 quitRequested = false;
1080
1081 keysactive[SDLK_ESCAPE] = false;
1082
1083 #ifdef WITH_NETWORK
1084 if (isNetworkGame)
1085 {
1086 if (!playerEndLevel)
1087 {
1088 network_prepare(PACKET_WAITING);
1089 network_send(4); // PACKET_WAITING
1090 } else {
1091 network_prepare(PACKET_GAME_QUIT);
1092 network_send(4); // PACKET_GAMEQUIT
1093 }
1094 }
1095 #endif
1096 }
1097
1098 #ifdef WITH_NETWORK
1099 if (isNetworkGame)
1100 {
1101 SDL_Surface *temp_surface = VGAScreen;
1102 VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
1103
1104 if (!yourInGameMenuRequest)
1105 {
1106 JE_barShade(VGAScreen, 3, 60, 257, 80); /*Help Box*/
1107 JE_barShade(VGAScreen, 5, 62, 255, 78);
1108 JE_dString(VGAScreen, 10, 65, "Other player in options menu.", SMALL_FONT_SHAPES);
1109 JE_showVGA();
1110
1111 while (true)
1112 {
1113 service_SDL_events(false);
1114 JE_showVGA();
1115
1116 if (packet_in[0])
1117 {
1118 if (SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_WAITING)
1119 {
1120 network_check();
1121 break;
1122 } else if (SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_GAME_QUIT) {
1123 reallyEndLevel = true;
1124 playerEndLevel = true;
1125
1126 network_check();
1127 break;
1128 }
1129 }
1130
1131 network_update();
1132 network_check();
1133
1134 SDL_Delay(16);
1135 }
1136 } else {
1137 /*
1138 JE_barShade(3, 160, 257, 180); /-*Help Box*-/
1139 JE_barShade(5, 162, 255, 178);
1140 tempScreenSeg = VGAScreen;
1141 JE_dString(VGAScreen, 10, 165, "Waiting for other player.", SMALL_FONT_SHAPES);
1142 JE_showVGA();
1143 */
1144 }
1145
1146 while (!network_is_sync())
1147 {
1148 service_SDL_events(false);
1149
1150 network_check();
1151 SDL_Delay(16);
1152 }
1153
1154 VGAScreen = temp_surface; /* side-effect of game_screen */
1155 }
1156 #endif
1157
1158 yourInGameMenuRequest = false;
1159
1160 //skipStarShowVGA = true;
1161 }
1162
JE_inGameSetup(void)1163 JE_boolean JE_inGameSetup( void )
1164 {
1165 SDL_Surface *temp_surface = VGAScreen;
1166 VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
1167
1168 JE_boolean returnvalue = false;
1169
1170 const JE_byte help[6] /* [1..6] */ = {15, 15, 28, 29, 26, 27};
1171 JE_byte sel;
1172 JE_boolean quit;
1173
1174 bool first = true;
1175
1176 //tempScreenSeg = VGAScreenSeg; /* <MXD> ? should work as VGAScreen */
1177
1178 quit = false;
1179 sel = 1;
1180
1181 JE_barShade(VGAScreen, 3, 13, 217, 137); /*Main Box*/
1182 JE_barShade(VGAScreen, 5, 15, 215, 135);
1183
1184 JE_barShade(VGAScreen, 3, 143, 257, 157); /*Help Box*/
1185 JE_barShade(VGAScreen, 5, 145, 255, 155);
1186 memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
1187
1188 do
1189 {
1190 memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
1191
1192 for (x = 0; x < 6; x++)
1193 {
1194 JE_outTextAdjust(VGAScreen, 10, (x + 1) * 20, inGameText[x], 15, ((sel == x+1) << 1) - 4, SMALL_FONT_SHAPES, true);
1195 }
1196
1197 JE_outTextAdjust(VGAScreen, 120, 3 * 20, detailLevel[processorType-1], 15, ((sel == 3) << 1) - 4, SMALL_FONT_SHAPES, true);
1198 JE_outTextAdjust(VGAScreen, 120, 4 * 20, gameSpeedText[gameSpeed-1], 15, ((sel == 4) << 1) - 4, SMALL_FONT_SHAPES, true);
1199
1200 JE_outTextAdjust(VGAScreen, 10, 147, mainMenuHelp[help[sel-1]-1], 14, 6, TINY_FONT, true);
1201
1202 JE_barDrawShadow(VGAScreen, 120, 20, 1, music_disabled ? 12 : 16, tyrMusicVolume / 12, 3, 13);
1203 JE_barDrawShadow(VGAScreen, 120, 40, 1, samples_disabled ? 12 : 16, fxVolume / 12, 3, 13);
1204
1205 JE_showVGA();
1206
1207 if (first)
1208 {
1209 first = false;
1210 wait_noinput(false, false, true); // TODO: should up the joystick repeat temporarily instead
1211 }
1212
1213 tempW = 0;
1214 JE_textMenuWait(&tempW, true);
1215
1216 if (inputDetected)
1217 {
1218 switch (lastkey_sym)
1219 {
1220 case SDLK_RETURN:
1221 JE_playSampleNum(S_SELECT);
1222 switch (sel)
1223 {
1224 case 1:
1225 music_disabled = !music_disabled;
1226 break;
1227 case 2:
1228 samples_disabled = !samples_disabled;
1229 break;
1230 case 3:
1231 case 4:
1232 sel = 5;
1233 break;
1234 case 5:
1235 quit = true;
1236 break;
1237 case 6:
1238 returnvalue = true;
1239 quit = true;
1240 if (constantPlay)
1241 {
1242 JE_tyrianHalt(0);
1243 }
1244
1245 if (isNetworkGame)
1246 { /*Tell other computer to exit*/
1247 haltGame = true;
1248 playerEndLevel = true;
1249 }
1250 break;
1251 }
1252 break;
1253 case SDLK_ESCAPE:
1254 quit = true;
1255 JE_playSampleNum(S_SPRING);
1256 break;
1257 case SDLK_UP:
1258 if (--sel < 1)
1259 {
1260 sel = 6;
1261 }
1262 JE_playSampleNum(S_CURSOR);
1263 break;
1264 case SDLK_DOWN:
1265 if (++sel > 6)
1266 {
1267 sel = 1;
1268 }
1269 JE_playSampleNum(S_CURSOR);
1270 break;
1271 case SDLK_LEFT:
1272 switch (sel)
1273 {
1274 case 1:
1275 JE_changeVolume(&tyrMusicVolume, -12, &fxVolume, 0);
1276 if (music_disabled)
1277 {
1278 music_disabled = false;
1279 restart_song();
1280 }
1281 break;
1282 case 2:
1283 JE_changeVolume(&tyrMusicVolume, 0, &fxVolume, -12);
1284 samples_disabled = false;
1285 break;
1286 case 3:
1287 if (--processorType < 1)
1288 {
1289 processorType = 4;
1290 }
1291 JE_initProcessorType();
1292 JE_setNewGameSpeed();
1293 break;
1294 case 4:
1295 if (--gameSpeed < 1)
1296 {
1297 gameSpeed = 5;
1298 }
1299 JE_initProcessorType();
1300 JE_setNewGameSpeed();
1301 break;
1302 }
1303 if (sel < 5)
1304 {
1305 JE_playSampleNum(S_CURSOR);
1306 }
1307 break;
1308 case SDLK_RIGHT:
1309 switch (sel)
1310 {
1311 case 1:
1312 JE_changeVolume(&tyrMusicVolume, 12, &fxVolume, 0);
1313 if (music_disabled)
1314 {
1315 music_disabled = false;
1316 restart_song();
1317 }
1318 break;
1319 case 2:
1320 JE_changeVolume(&tyrMusicVolume, 0, &fxVolume, 12);
1321 samples_disabled = false;
1322 break;
1323 case 3:
1324 if (++processorType > 4)
1325 {
1326 processorType = 1;
1327 }
1328 JE_initProcessorType();
1329 JE_setNewGameSpeed();
1330 break;
1331 case 4:
1332 if (++gameSpeed > 5)
1333 {
1334 gameSpeed = 1;
1335 }
1336 JE_initProcessorType();
1337 JE_setNewGameSpeed();
1338 break;
1339 }
1340 if (sel < 5)
1341 {
1342 JE_playSampleNum(S_CURSOR);
1343 }
1344 break;
1345 case SDLK_w:
1346 if (sel == 3)
1347 {
1348 processorType = 6;
1349 JE_initProcessorType();
1350 }
1351 default:
1352 break;
1353 }
1354 }
1355
1356 } while (!(quit || haltGame));
1357
1358 VGAScreen = temp_surface; /* side-effect of game_screen */
1359
1360 return returnvalue;
1361 }
1362
JE_inGameHelp(void)1363 void JE_inGameHelp( void )
1364 {
1365 SDL_Surface *temp_surface = VGAScreen;
1366 VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
1367
1368 //tempScreenSeg = VGAScreenSeg;
1369
1370 JE_clearKeyboard();
1371 JE_wipeKey();
1372
1373 JE_barShade(VGAScreen, 1, 1, 262, 182); /*Main Box*/
1374 JE_barShade(VGAScreen, 3, 3, 260, 180);
1375 JE_barShade(VGAScreen, 5, 5, 258, 178);
1376 JE_barShade(VGAScreen, 7, 7, 256, 176);
1377 fill_rectangle_xy(VGAScreen, 9, 9, 254, 174, 0);
1378
1379 if (twoPlayerMode) // Two-Player Help
1380 {
1381 helpBoxColor = 3;
1382 helpBoxBrightness = 3;
1383 JE_HBox(VGAScreen, 20, 4, 36, 50);
1384
1385 // weapon help
1386 blit_sprite(VGAScreenSeg, 2, 21, OPTION_SHAPES, 43);
1387 helpBoxColor = 5;
1388 helpBoxBrightness = 3;
1389 JE_HBox(VGAScreen, 55, 20, 37, 40);
1390
1391 // sidekick help
1392 blit_sprite(VGAScreenSeg, 5, 36, OPTION_SHAPES, 41);
1393 helpBoxColor = 5;
1394 helpBoxBrightness = 3;
1395 JE_HBox(VGAScreen, 40, 43, 34, 44);
1396
1397 // sheild/armor help
1398 blit_sprite(VGAScreenSeg, 2, 79, OPTION_SHAPES, 42);
1399 helpBoxColor = 5;
1400 helpBoxBrightness = 3;
1401 JE_HBox(VGAScreen, 54, 84, 35, 40);
1402
1403 helpBoxColor = 5;
1404 helpBoxBrightness = 3;
1405 JE_HBox(VGAScreen, 5, 126, 38, 55);
1406 helpBoxColor = 5;
1407 helpBoxBrightness = 3;
1408 JE_HBox(VGAScreen, 5, 160, 39, 55);
1409 }
1410 else
1411 {
1412 // power bar help
1413 blit_sprite(VGAScreenSeg, 15, 5, OPTION_SHAPES, 40);
1414 helpBoxColor = 5;
1415 helpBoxBrightness = 3;
1416 JE_HBox(VGAScreen, 40, 10, 31, 45);
1417
1418 // weapon help
1419 blit_sprite(VGAScreenSeg, 5, 37, OPTION_SHAPES, 39);
1420 helpBoxColor = 5;
1421 helpBoxBrightness = 3;
1422 JE_HBox(VGAScreen, 40, 40, 32, 44);
1423 helpBoxColor = 5;
1424 helpBoxBrightness = 3;
1425 JE_HBox(VGAScreen, 40, 60, 33, 44);
1426
1427 // sidekick help
1428 blit_sprite(VGAScreenSeg, 5, 98, OPTION_SHAPES, 41);
1429 helpBoxColor = 5;
1430 helpBoxBrightness = 3;
1431 JE_HBox(VGAScreen, 40, 103, 34, 44);
1432
1433 // shield/armor help
1434 blit_sprite(VGAScreenSeg, 2, 138, OPTION_SHAPES, 42);
1435 helpBoxColor = 5;
1436 helpBoxBrightness = 3;
1437 JE_HBox(VGAScreen, 54, 143, 35, 40);
1438 }
1439
1440 // "press a key"
1441 blit_sprite(VGAScreenSeg, 16, 189, OPTION_SHAPES, 36); // in-game text area
1442 JE_outText(VGAScreenSeg, 120 - JE_textWidth(miscText[5-1], TINY_FONT) / 2 + 20, 190, miscText[5-1], 0, 4);
1443
1444 JE_showVGA();
1445
1446 do
1447 {
1448 tempW = 0;
1449 JE_textMenuWait(&tempW, true);
1450 }
1451 while (!inputDetected);
1452
1453 textErase = 1;
1454
1455 VGAScreen = temp_surface;
1456 }
1457
JE_highScoreCheck(void)1458 void JE_highScoreCheck( void )
1459 {
1460 free_sprite2s(&shapes6);
1461 JE_loadCompShapes(&shapes6, '1'); // need mouse cursor sprite
1462
1463 Sint32 temp_score;
1464
1465 for (int temp_p = 0; temp_p < (twoPlayerMode ? 2 : 1); ++temp_p)
1466 {
1467 JE_sortHighScores();
1468
1469 int p = temp_p;
1470
1471 if (twoPlayerMode)
1472 {
1473 // ask for the highest scorer first
1474 if (player[0].cash < player[1].cash)
1475 p = (temp_p == 0) ? 1 : 0;
1476
1477 temp_score = (p == 0) ? player[0].cash : player[1].cash;
1478 }
1479 else
1480 {
1481 // single player highscore includes cost of upgrades
1482 temp_score = JE_totalScore(&player[0]);
1483 }
1484
1485 int slot;
1486 const int first_slot = (initial_episode_num - 1) * 6 + (twoPlayerMode ? 3 : 0),
1487 slot_limit = first_slot + 3;
1488
1489 for (slot = first_slot; slot < slot_limit; ++slot)
1490 {
1491 if (temp_score > saveFiles[slot].highScore1)
1492 break;
1493 }
1494
1495 // did you get a high score?
1496 if (slot < slot_limit)
1497 {
1498 // shift down old scores
1499 for (int i = slot_limit - 1; i > slot; --i)
1500 {
1501 saveFiles[i].highScore1 = saveFiles[i - 1].highScore1;
1502 strcpy(saveFiles[i].highScoreName, saveFiles[i - 1].highScoreName);
1503 }
1504
1505 wait_noinput(false, true, false);
1506
1507 JE_clr256(VGAScreen);
1508 JE_showVGA();
1509 memcpy(colors, palettes[0], sizeof(colors));
1510
1511 play_song(33);
1512
1513 {
1514 /* Enter Thy name */
1515
1516 JE_byte flash = 8 * 16 + 10;
1517 JE_boolean fadein = true;
1518 JE_boolean quit = false, cancel = false;
1519 char stemp[30], tempstr[30];
1520 char buffer[256];
1521
1522 strcpy(stemp, " ");
1523 temp = 0;
1524
1525 JE_barShade(VGAScreen, 65, 55, 255, 155);
1526
1527 do
1528 {
1529 service_SDL_events(true);
1530
1531 JE_dString(VGAScreen, JE_fontCenter(miscText[51], FONT_SHAPES), 3, miscText[51], FONT_SHAPES);
1532
1533 temp3 = twoPlayerMode ? 58 + p : 53;
1534
1535 JE_dString(VGAScreen, JE_fontCenter(miscText[temp3-1], SMALL_FONT_SHAPES), 30, miscText[temp3-1], SMALL_FONT_SHAPES);
1536
1537 blit_sprite(VGAScreenSeg, 50, 50, OPTION_SHAPES, 35); // message box
1538
1539 if (twoPlayerMode)
1540 {
1541 sprintf(buffer, "%s %s", miscText[48 + p], miscText[53]);
1542 JE_textShade(VGAScreen, 60, 55, buffer, 11, 4, FULL_SHADE);
1543 }
1544 else
1545 {
1546 JE_textShade(VGAScreen, 60, 55, miscText[53], 11, 4, FULL_SHADE);
1547 }
1548
1549 sprintf(buffer, "%s %d", miscText[37], temp_score);
1550 JE_textShade(VGAScreen, 70, 70, buffer, 11, 4, FULL_SHADE);
1551
1552 do
1553 {
1554 flash = (flash == 8 * 16 + 10) ? 8 * 16 + 2 : 8 * 16 + 10;
1555 temp3 = (temp3 == 6) ? 2 : 6;
1556
1557 strncpy(tempstr, stemp, temp);
1558 tempstr[temp] = '\0';
1559 JE_outText(VGAScreen, 65, 89, tempstr, 8, 3);
1560 tempW = 65 + JE_textWidth(tempstr, TINY_FONT);
1561 JE_barShade(VGAScreen, tempW + 2, 90, tempW + 6, 95);
1562 fill_rectangle_xy(VGAScreen, tempW + 1, 89, tempW + 5, 94, flash);
1563
1564 for (int i = 0; i < 14; i++)
1565 {
1566 setjasondelay(1);
1567
1568 JE_mouseStart();
1569 JE_showVGA();
1570 if (fadein)
1571 {
1572 fade_palette(colors, 15, 0, 255);
1573 fadein = false;
1574 }
1575 JE_mouseReplace();
1576
1577 push_joysticks_as_keyboard();
1578 service_wait_delay();
1579
1580 if (newkey || newmouse)
1581 break;
1582 }
1583
1584 } while (!newkey && !newmouse);
1585
1586 if (!playing)
1587 play_song(31);
1588
1589 if (mouseButton > 0)
1590 {
1591 if (mouseX > 56 && mouseX < 142 && mouseY > 123 && mouseY < 149)
1592 {
1593 quit = true;
1594 }
1595 else if (mouseX > 151 && mouseX < 237 && mouseY > 123 && mouseY < 149)
1596 {
1597 quit = true;
1598 cancel = true;
1599 }
1600 }
1601 else if (newkey)
1602 {
1603 bool validkey = false;
1604 lastkey_char = toupper(lastkey_char);
1605 switch(lastkey_char)
1606 {
1607 case ' ':
1608 case '-':
1609 case '.':
1610 case ',':
1611 case ':':
1612 case '!':
1613 case '?':
1614 case '#':
1615 case '@':
1616 case '$':
1617 case '%':
1618 case '*':
1619 case '(':
1620 case ')':
1621 case '/':
1622 case '=':
1623 case '+':
1624 case '<':
1625 case '>':
1626 case ';':
1627 case '"':
1628 case '\'':
1629 validkey = true;
1630 default:
1631 if (temp < 28 && (validkey || (lastkey_char >= 'A' && lastkey_char <= 'Z') || (lastkey_char >= '0' && lastkey_char <= '9')))
1632 {
1633 stemp[temp] = lastkey_char;
1634 temp++;
1635 }
1636 break;
1637 case SDLK_BACKSPACE:
1638 case SDLK_DELETE:
1639 if (temp)
1640 {
1641 temp--;
1642 stemp[temp] = ' ';
1643 }
1644 break;
1645 case SDLK_ESCAPE:
1646 quit = true;
1647 cancel = true;
1648 break;
1649 case SDLK_RETURN:
1650 quit = true;
1651 break;
1652 }
1653 }
1654 }
1655 while (!quit);
1656
1657 if (!cancel)
1658 {
1659 saveFiles[slot].highScore1 = temp_score;
1660 strcpy(saveFiles[slot].highScoreName, stemp);
1661 saveFiles[slot].highScoreDiff = difficultyLevel;
1662 }
1663
1664 fade_black(15);
1665 JE_loadPic(VGAScreen, 2, false);
1666
1667 JE_dString(VGAScreen, JE_fontCenter(miscText[50], FONT_SHAPES), 10, miscText[50], FONT_SHAPES);
1668 JE_dString(VGAScreen, JE_fontCenter(episode_name[episodeNum], SMALL_FONT_SHAPES), 35, episode_name[episodeNum], SMALL_FONT_SHAPES);
1669
1670 for (int i = first_slot; i < slot_limit; ++i)
1671 {
1672 if (i != slot)
1673 {
1674 sprintf(buffer, "~#%d:~ %d", (i - first_slot + 1), saveFiles[i].highScore1);
1675 JE_textShade(VGAScreen, 20, ((i - first_slot + 1) * 12) + 65, buffer, 15, 0, FULL_SHADE);
1676 JE_textShade(VGAScreen, 150, ((i - first_slot + 1) * 12) + 65, saveFiles[i].highScoreName, 15, 2, FULL_SHADE);
1677 }
1678 }
1679
1680 JE_showVGA();
1681
1682 fade_palette(colors, 15, 0, 255);
1683
1684 sprintf(buffer, "~#%d:~ %d", (slot - first_slot + 1), saveFiles[slot].highScore1);
1685
1686 frameCountMax = 6;
1687 textGlowFont = TINY_FONT;
1688
1689 textGlowBrightness = 10;
1690 JE_outTextGlow(VGAScreenSeg, 20, (slot - first_slot + 1) * 12 + 65, buffer);
1691 textGlowBrightness = 10;
1692 JE_outTextGlow(VGAScreenSeg, 150, (slot - first_slot + 1) * 12 + 65, saveFiles[slot].highScoreName);
1693 textGlowBrightness = 10;
1694 JE_outTextGlow(VGAScreenSeg, JE_fontCenter(miscText[4], TINY_FONT), 180, miscText[4]);
1695
1696 JE_showVGA();
1697
1698 if (frameCountMax != 0)
1699 wait_input(true, true, true);
1700
1701 fade_black(15);
1702 }
1703
1704 }
1705 }
1706 }
1707
1708 // increases game difficulty based on player's total score / total of players' scores
adjust_difficulty(void)1709 void adjust_difficulty( void )
1710 {
1711 const float score_multiplier[10] =
1712 {
1713 0, // Wimp (doesn't exist)
1714 0.4f, // Easy
1715 0.8f, // Normal
1716 1.3f, // Hard
1717 1.6f, // Impossible
1718 2, // Insanity
1719 2, // Suicide
1720 3, // Maniacal
1721 3, // Zinglon
1722 3, // Nortaneous
1723 };
1724
1725 assert(initialDifficulty > 0 && initialDifficulty < 10);
1726
1727 const ulong score = twoPlayerMode ? (player[0].cash + player[1].cash) : JE_totalScore(&player[0]),
1728 adjusted_score = roundf(score * score_multiplier[initialDifficulty]);
1729
1730 uint new_difficulty = 0;
1731
1732 if (twoPlayerMode)
1733 {
1734 if (adjusted_score < 10000)
1735 new_difficulty = 1; // Easy
1736 else if (adjusted_score < 20000)
1737 new_difficulty = 2; // Normal
1738 else if (adjusted_score < 50000)
1739 new_difficulty = 3; // Hard
1740 else if (adjusted_score < 80000)
1741 new_difficulty = 4; // Impossible
1742 else if (adjusted_score < 125000)
1743 new_difficulty = 5; // Insanity
1744 else if (adjusted_score < 200000)
1745 new_difficulty = 6; // Suicide
1746 else if (adjusted_score < 400000)
1747 new_difficulty = 7; // Maniacal
1748 else if (adjusted_score < 600000)
1749 new_difficulty = 8; // Zinglon
1750 else
1751 new_difficulty = 9; // Nortaneous
1752 }
1753 else
1754 {
1755 if (adjusted_score < 40000)
1756 new_difficulty = 1; // Easy
1757 else if (adjusted_score < 70000)
1758 new_difficulty = 2; // Normal
1759 else if (adjusted_score < 150000)
1760 new_difficulty = 3; // Hard
1761 else if (adjusted_score < 300000)
1762 new_difficulty = 4; // Impossible
1763 else if (adjusted_score < 600000)
1764 new_difficulty = 5; // Insanity
1765 else if (adjusted_score < 1000000)
1766 new_difficulty = 6; // Suicide
1767 else if (adjusted_score < 2000000)
1768 new_difficulty = 7; // Maniacal
1769 else if (adjusted_score < 3000000)
1770 new_difficulty = 8; // Zinglon
1771 else
1772 new_difficulty = 9; // Nortaneous
1773 }
1774
1775 difficultyLevel = MAX((unsigned)difficultyLevel, new_difficulty);
1776 }
1777
load_next_demo(void)1778 bool load_next_demo( void )
1779 {
1780 if (++demo_num > 5)
1781 demo_num = 1;
1782
1783 char demo_filename[9];
1784 snprintf(demo_filename, sizeof(demo_filename), "demo.%d", demo_num);
1785 demo_file = dir_fopen_die(data_dir(), demo_filename, "rb"); // TODO: only play demos from existing file (instead of dying)
1786
1787 difficultyLevel = 2;
1788 bonusLevelCurrent = false;
1789
1790 Uint8 temp = fgetc(demo_file);
1791 JE_initEpisode(temp);
1792 efread(levelName, 1, 10, demo_file); levelName[10] = '\0';
1793 lvlFileNum = fgetc(demo_file);
1794
1795 player[0].items.weapon[FRONT_WEAPON].id = fgetc(demo_file);
1796 player[0].items.weapon[REAR_WEAPON].id = fgetc(demo_file);
1797 player[0].items.super_arcade_mode = fgetc(demo_file);
1798 player[0].items.sidekick[LEFT_SIDEKICK] = fgetc(demo_file);
1799 player[0].items.sidekick[RIGHT_SIDEKICK] = fgetc(demo_file);
1800 player[0].items.generator = fgetc(demo_file);
1801
1802 player[0].items.sidekick_level = fgetc(demo_file); // could probably ignore
1803 player[0].items.sidekick_series = fgetc(demo_file); // could probably ignore
1804
1805 initial_episode_num = fgetc(demo_file); // could probably ignore
1806
1807 player[0].items.shield = fgetc(demo_file);
1808 player[0].items.special = fgetc(demo_file);
1809 player[0].items.ship = fgetc(demo_file);
1810
1811 for (uint i = 0; i < 2; ++i)
1812 player[0].items.weapon[i].power = fgetc(demo_file);
1813
1814 fseek(demo_file, 3, SEEK_CUR);
1815
1816 levelSong = fgetc(demo_file);
1817
1818 demo_keys_wait = 0;
1819 demo_keys = next_demo_keys = 0;
1820
1821 printf("loaded demo '%s'\n", demo_filename);
1822
1823 return true;
1824 }
1825
replay_demo_keys(void)1826 bool replay_demo_keys( void )
1827 {
1828 if (demo_keys_wait == 0)
1829 if (read_demo_keys() == false)
1830 return false; // no more keys
1831
1832 if (demo_keys_wait > 0)
1833 demo_keys_wait--;
1834
1835 if (demo_keys & (1 << 0))
1836 player[0].y -= CURRENT_KEY_SPEED;
1837 if (demo_keys & (1 << 1))
1838 player[0].y += CURRENT_KEY_SPEED;
1839
1840 if (demo_keys & (1 << 2))
1841 player[0].x -= CURRENT_KEY_SPEED;
1842 if (demo_keys & (1 << 3))
1843 player[0].x += CURRENT_KEY_SPEED;
1844
1845 button[0] = (bool)(demo_keys & (1 << 4));
1846 button[3] = (bool)(demo_keys & (1 << 5));
1847 button[1] = (bool)(demo_keys & (1 << 6));
1848 button[2] = (bool)(demo_keys & (1 << 7));
1849
1850 return true;
1851 }
1852
read_demo_keys(void)1853 bool read_demo_keys( void )
1854 {
1855 demo_keys = next_demo_keys;
1856
1857 efread(&demo_keys_wait, sizeof(Uint16), 1, demo_file);
1858 demo_keys_wait = SDL_Swap16(demo_keys_wait);
1859
1860 next_demo_keys = getc(demo_file);
1861
1862 return !feof(demo_file);
1863 }
1864
1865 /*Street Fighter codes*/
JE_SFCodes(JE_byte playerNum_,JE_integer PX_,JE_integer PY_,JE_integer mouseX_,JE_integer mouseY_)1866 void JE_SFCodes( JE_byte playerNum_, JE_integer PX_, JE_integer PY_, JE_integer mouseX_, JE_integer mouseY_ )
1867 {
1868 JE_byte temp, temp2, temp3, temp4, temp5;
1869
1870 uint ship = player[playerNum_-1].items.ship;
1871
1872 /*Get direction*/
1873 if (playerNum_ == 2 && ship < 15)
1874 {
1875 ship = 0;
1876 }
1877
1878 if (ship < 15)
1879 {
1880
1881 temp2 = (mouseY_ > PY_) + /*UP*/
1882 (mouseY_ < PY_) + /*DOWN*/
1883 (PX_ < mouseX_) + /*LEFT*/
1884 (PX_ > mouseX_); /*RIGHT*/
1885 temp = (mouseY_ > PY_) * 1 + /*UP*/
1886 (mouseY_ < PY_) * 2 + /*DOWN*/
1887 (PX_ < mouseX_) * 3 + /*LEFT*/
1888 (PX_ > mouseX_) * 4; /*RIGHT*/
1889
1890 if (temp == 0) // no direction being pressed
1891 {
1892 if (!button[0]) // if fire button is released
1893 {
1894 temp = 9;
1895 temp2 = 1;
1896 } else {
1897 temp2 = 0;
1898 temp = 99;
1899 }
1900 }
1901
1902 if (temp2 == 1) // if exactly one direction pressed or firebutton is released
1903 {
1904 temp += button[0] * 4;
1905
1906 temp3 = superTyrian ? 21 : 3;
1907 for (temp2 = 0; temp2 < temp3; temp2++)
1908 {
1909
1910 /*Use SuperTyrian ShipCombos or not?*/
1911 temp5 = superTyrian ? shipCombosB[temp2] : shipCombos[ship][temp2];
1912
1913 // temp5 == selected combo in ship
1914 if (temp5 == 0) /* combo doesn't exists */
1915 {
1916 // mark twiddles as cancelled/finished
1917 SFCurrentCode[playerNum_-1][temp2] = 0;
1918 } else {
1919 // get next combo key
1920 temp4 = keyboardCombos[temp5-1][SFCurrentCode[playerNum_-1][temp2]];
1921
1922 // correct key
1923 if (temp4 == temp)
1924 {
1925 SFCurrentCode[playerNum_-1][temp2]++;
1926
1927 temp4 = keyboardCombos[temp5-1][SFCurrentCode[playerNum_-1][temp2]];
1928 if (temp4 > 100 && temp4 <= 100 + SPECIAL_NUM)
1929 {
1930 SFCurrentCode[playerNum_-1][temp2] = 0;
1931 SFExecuted[playerNum_-1] = temp4 - 100;
1932 }
1933 } else {
1934 if ((temp != 9) &&
1935 (temp4 - 1) % 4 != (temp - 1) % 4 &&
1936 (SFCurrentCode[playerNum_-1][temp2] == 0 ||
1937 keyboardCombos[temp5-1][SFCurrentCode[playerNum_-1][temp2]-1] != temp))
1938 {
1939 SFCurrentCode[playerNum_-1][temp2] = 0;
1940 }
1941 }
1942 }
1943 }
1944 }
1945
1946 }
1947 }
1948
JE_sort(void)1949 void JE_sort( void )
1950 {
1951 JE_byte a, b;
1952
1953 for (a = 0; a < 2; a++)
1954 {
1955 for (b = a + 1; b < 3; b++)
1956 {
1957 if (saveFiles[temp + a].highScore1 < saveFiles[temp + b].highScore1)
1958 {
1959 JE_longint tempLI;
1960 char tempStr[30];
1961 JE_byte tempByte;
1962
1963 tempLI = saveFiles[temp + a].highScore1;
1964 saveFiles[temp + a].highScore1 = saveFiles[temp + b].highScore1;
1965 saveFiles[temp + b].highScore1 = tempLI;
1966
1967 strcpy(tempStr, saveFiles[temp + a].highScoreName);
1968 strcpy(saveFiles[temp + a].highScoreName, saveFiles[temp + b].highScoreName);
1969 strcpy(saveFiles[temp + b].highScoreName, tempStr);
1970
1971 tempByte = saveFiles[temp + a].highScoreDiff;
1972 saveFiles[temp + a].highScoreDiff = saveFiles[temp + b].highScoreDiff;
1973 saveFiles[temp + b].highScoreDiff = tempByte;
1974 }
1975 }
1976 }
1977 }
1978
JE_playCredits(void)1979 void JE_playCredits( void )
1980 {
1981 const int lines_max = 132;
1982 const int line_max_length = 65;
1983
1984 char credstr[lines_max][line_max_length + 1];
1985
1986 int lines = 0;
1987
1988 JE_byte currentpic = 0, fade = 0;
1989 JE_shortint fadechg = 1;
1990 JE_byte currentship = 0;
1991 JE_integer shipx = 0, shipxwait = 0;
1992 JE_shortint shipxc = 0, shipxca = 0;
1993
1994 load_sprites_file(EXTRA_SHAPES, "estsc.shp");
1995
1996 setjasondelay2(1000);
1997
1998 play_song(8);
1999
2000 // load credits text
2001 FILE *f = dir_fopen_die(data_dir(), "tyrian.cdt", "rb");
2002 for (lines = 0; !feof(f) && lines < lines_max; ++lines)
2003 {
2004 read_encrypted_pascal_string(credstr[lines], sizeof(credstr[lines]), f);
2005 }
2006 if (lines == lines_max)
2007 --lines;
2008 fclose(f);
2009
2010 memcpy(colors, palettes[6-1], sizeof(colors));
2011 JE_clr256(VGAScreen);
2012 JE_showVGA();
2013 fade_palette(colors, 2, 0, 255);
2014
2015 //tempScreenSeg = VGAScreenSeg;
2016
2017 const int ticks_max = lines * 20 * 3;
2018 for (int ticks = 0; ticks < ticks_max; ++ticks)
2019 {
2020 setjasondelay(1);
2021 JE_clr256(VGAScreen);
2022
2023 blit_sprite_hv(VGAScreenSeg, 319 - sprite(EXTRA_SHAPES, currentpic)->width, 100 - (sprite(EXTRA_SHAPES, currentpic)->height / 2), EXTRA_SHAPES, currentpic, 0x0, fade - 15);
2024
2025 fade += fadechg;
2026 if (fade == 0 && fadechg == -1)
2027 {
2028 fadechg = 1;
2029 ++currentpic;
2030 if (currentpic >= sprite_table[EXTRA_SHAPES].count)
2031 currentpic = 0;
2032 }
2033 if (fade == 15)
2034 fadechg = 0;
2035
2036 if (delaycount2() == 0)
2037 {
2038 fadechg = -1;
2039 setjasondelay2(900);
2040 }
2041
2042 if (ticks % 200 == 0)
2043 {
2044 currentship = (mt_rand() % 11) + 1;
2045 shipxwait = (mt_rand() % 80) + 10;
2046 if ((mt_rand() % 2) == 1)
2047 {
2048 shipx = 1;
2049 shipxc = 0;
2050 shipxca = 1;
2051 }
2052 else
2053 {
2054 shipx = 900;
2055 shipxc = 0;
2056 shipxca = -1;
2057 }
2058 }
2059
2060 shipxwait--;
2061 if (shipxwait == 0)
2062 {
2063 if (shipx == 1 || shipx == 900)
2064 shipxc = 0;
2065 shipxca = -shipxca;
2066 shipxwait = (mt_rand() % 40) + 15;
2067 }
2068 shipxc += shipxca;
2069 shipx += shipxc;
2070 if (shipx < 1)
2071 {
2072 shipx = 1;
2073 shipxwait = 1;
2074 }
2075 if (shipx > 900)
2076 {
2077 shipx = 900;
2078 shipxwait = 1;
2079 }
2080 int tmp_unknown = shipxc * shipxc;
2081 if (450 + tmp_unknown < 0 || 450 + tmp_unknown > 900)
2082 {
2083 if (shipxca < 0 && shipxc < 0)
2084 shipxwait = 1;
2085 if (shipxca > 0 && shipxc > 0)
2086 shipxwait = 1;
2087 }
2088
2089 uint ship_sprite = ships[currentship].shipgraphic;
2090 if (shipxc < -10)
2091 ship_sprite -= (shipxc < -20) ? 4 : 2;
2092 else if (shipxc > 10)
2093 ship_sprite += (shipxc > 20) ? 4 : 2;
2094
2095 blit_sprite2x2(VGAScreen, shipx / 40, 184 - (ticks % 200), shapes9, ship_sprite);
2096
2097 const int bottom_line = (ticks / 3) / 20;
2098 int y = 20 - ((ticks / 3) % 20);
2099
2100 for (int line = bottom_line - 10; line < bottom_line; ++line)
2101 {
2102 if (line >= 0 && line < lines_max)
2103 {
2104 if (strcmp(&credstr[line][0], ".") != 0 && strlen(credstr[line]))
2105 {
2106 const Uint8 color = credstr[line][0] - 65;
2107 const char *text = &credstr[line][1];
2108
2109 const int x = 110 - JE_textWidth(text, SMALL_FONT_SHAPES) / 2;
2110
2111 JE_outTextAdjust(VGAScreen, x + abs((y / 18) % 4 - 2) - 1, y - 1, text, color, -8, SMALL_FONT_SHAPES, false);
2112 JE_outTextAdjust(VGAScreen, x, y, text, color, -2, SMALL_FONT_SHAPES, false);
2113 }
2114 }
2115
2116 y += 20;
2117 }
2118
2119 fill_rectangle_xy(VGAScreen, 0, 0, 319, 10, 0);
2120 fill_rectangle_xy(VGAScreen, 0, 190, 319, 199, 0);
2121
2122 if (currentpic == sprite_table[EXTRA_SHAPES].count - 1)
2123 JE_outTextAdjust(VGAScreen, 5, 180, miscText[54], 2, -2, SMALL_FONT_SHAPES, false); // levels-in-episode
2124
2125 if (bottom_line == lines_max - 8)
2126 fade_song();
2127
2128 if (ticks == ticks_max - 1)
2129 {
2130 --ticks;
2131 play_song(9);
2132 }
2133
2134 NETWORK_KEEP_ALIVE();
2135
2136 JE_showVGA();
2137
2138 wait_delay();
2139
2140 if (JE_anyButton())
2141 break;
2142 }
2143
2144 fade_black(10);
2145
2146 free_sprites(EXTRA_SHAPES);
2147 }
2148
JE_endLevelAni(void)2149 void JE_endLevelAni( void )
2150 {
2151 JE_word x, y;
2152 JE_byte temp;
2153 char tempStr[256];
2154
2155 Sint8 i;
2156
2157 if (!constantPlay)
2158 {
2159 // grant shipedit privileges
2160
2161 // special
2162 if (player[0].items.special < 21)
2163 saveTemp[SAVE_FILES_SIZE + 81 + player[0].items.special] = 1;
2164
2165 for (uint p = 0; p < COUNTOF(player); ++p)
2166 {
2167 // front, rear
2168 for (uint i = 0; i < COUNTOF(player[p].items.weapon); ++i)
2169 saveTemp[SAVE_FILES_SIZE + player[p].items.weapon[i].id] = 1;
2170
2171 // options
2172 for (uint i = 0; i < COUNTOF(player[p].items.sidekick); ++i)
2173 saveTemp[SAVE_FILES_SIZE + 51 + player[p].items.sidekick[i]] = 1;
2174 }
2175 }
2176
2177 adjust_difficulty();
2178
2179 player[0].last_items = player[0].items;
2180 strcpy(lastLevelName, levelName);
2181
2182 JE_wipeKey();
2183 frameCountMax = 4;
2184 textGlowFont = SMALL_FONT_SHAPES;
2185
2186 SDL_Color white = { 255, 255, 255 };
2187 set_colors(white, 254, 254);
2188
2189 if (!levelTimer || levelTimerCountdown > 0 || !(episodeNum == 4))
2190 JE_playSampleNum(V_LEVEL_END);
2191 else
2192 play_song(21);
2193
2194 if (bonusLevel)
2195 {
2196 JE_outTextGlow(VGAScreenSeg, 20, 20, miscText[17-1]);
2197 }
2198 else if (all_players_alive())
2199 {
2200 sprintf(tempStr, "%s %s", miscText[27-1], levelName); // "Completed"
2201 JE_outTextGlow(VGAScreenSeg, 20, 20, tempStr);
2202 }
2203 else
2204 {
2205 sprintf(tempStr, "%s %s", miscText[62-1], levelName); // "Exiting"
2206 JE_outTextGlow(VGAScreenSeg, 20, 20, tempStr);
2207 }
2208
2209 if (twoPlayerMode)
2210 {
2211 for (uint i = 0; i < 2; ++i)
2212 {
2213 snprintf(tempStr, sizeof(tempStr), "%s %lu", miscText[40 + i], player[i].cash);
2214 JE_outTextGlow(VGAScreenSeg, 30, 50 + 20 * i, tempStr);
2215 }
2216 }
2217 else
2218 {
2219 sprintf(tempStr, "%s %lu", miscText[28-1], player[0].cash);
2220 JE_outTextGlow(VGAScreenSeg, 30, 50, tempStr);
2221 }
2222
2223 temp = (totalEnemy == 0) ? 0 : roundf(enemyKilled * 100 / totalEnemy);
2224 sprintf(tempStr, "%s %d%%", miscText[63-1], temp);
2225 JE_outTextGlow(VGAScreenSeg, 40, 90, tempStr);
2226
2227 if (!constantPlay)
2228 editorLevel += temp / 5;
2229
2230 if (!onePlayerAction && !twoPlayerMode)
2231 {
2232 JE_outTextGlow(VGAScreenSeg, 30, 120, miscText[4-1]); /*Cubes*/
2233
2234 if (cubeMax > 0)
2235 {
2236 if (cubeMax > 4)
2237 cubeMax = 4;
2238
2239 if (frameCountMax != 0)
2240 frameCountMax = 1;
2241
2242 for (temp = 1; temp <= cubeMax; temp++)
2243 {
2244 NETWORK_KEEP_ALIVE();
2245
2246 JE_playSampleNum(18);
2247 x = 20 + 30 * temp;
2248 y = 135;
2249 JE_drawCube(VGAScreenSeg, x, y, 9, 0);
2250 JE_showVGA();
2251
2252 for (i = -15; i <= 10; i++)
2253 {
2254 setjasondelay(frameCountMax);
2255
2256 blit_sprite_hv(VGAScreenSeg, x, y, OPTION_SHAPES, 25, 0x9, i);
2257
2258 if (JE_anyButton())
2259 frameCountMax = 0;
2260
2261 JE_showVGA();
2262
2263 wait_delay();
2264 }
2265 for (i = 10; i >= 0; i--)
2266 {
2267 setjasondelay(frameCountMax);
2268
2269 blit_sprite_hv(VGAScreenSeg, x, y, OPTION_SHAPES, 25, 0x9, i);
2270
2271 if (JE_anyButton())
2272 frameCountMax = 0;
2273
2274 JE_showVGA();
2275
2276 wait_delay();
2277 }
2278 }
2279 }
2280 else
2281 {
2282 JE_outTextGlow(VGAScreenSeg, 50, 135, miscText[15-1]);
2283 }
2284
2285 }
2286
2287 if (frameCountMax != 0)
2288 {
2289 frameCountMax = 6;
2290 temp = 1;
2291 } else {
2292 temp = 0;
2293 }
2294 temp2 = twoPlayerMode ? 150 : 160;
2295 JE_outTextGlow(VGAScreenSeg, 90, temp2, miscText[5-1]);
2296
2297 if (!constantPlay)
2298 {
2299 do
2300 {
2301 setjasondelay(1);
2302
2303 NETWORK_KEEP_ALIVE();
2304
2305 wait_delay();
2306 } while (!(JE_anyButton() || (frameCountMax == 0 && temp == 1)));
2307 }
2308
2309 wait_noinput(false, false, true); // TODO: should up the joystick repeat temporarily instead
2310
2311 fade_black(15);
2312 JE_clr256(VGAScreen);
2313 }
2314
JE_drawCube(SDL_Surface * screen,JE_word x,JE_word y,JE_byte filter,JE_byte brightness)2315 void JE_drawCube( SDL_Surface * screen, JE_word x, JE_word y, JE_byte filter, JE_byte brightness )
2316 {
2317 blit_sprite_dark(screen, x + 4, y + 4, OPTION_SHAPES, 25, false);
2318 blit_sprite_dark(screen, x + 3, y + 3, OPTION_SHAPES, 25, false);
2319 blit_sprite_hv(screen, x, y, OPTION_SHAPES, 25, filter, brightness);
2320 }
2321
JE_handleChat(void)2322 void JE_handleChat( void )
2323 {
2324 // STUB(); Annoying piece of crap =P
2325 }
2326
str_pop_int(char * str,int * val)2327 bool str_pop_int( char *str, int *val )
2328 {
2329 bool success = false;
2330
2331 char buf[256];
2332 assert(strlen(str) < sizeof(buf));
2333
2334 // grab the value from str
2335 char *end;
2336 *val = strtol(str, &end, 10);
2337
2338 if (end != str)
2339 {
2340 success = true;
2341
2342 // shift the rest to the beginning
2343 strcpy(buf, end);
2344 strcpy(str, buf);
2345 }
2346
2347 return success;
2348 }
2349
JE_operation(JE_byte slot)2350 void JE_operation( JE_byte slot )
2351 {
2352 JE_byte flash;
2353 char stemp[21];
2354 char tempStr[51];
2355
2356 if (!performSave)
2357 {
2358 if (saveFiles[slot-1].level > 0)
2359 {
2360 gameJustLoaded = true;
2361 JE_loadGame(slot);
2362 gameLoaded = true;
2363 }
2364 }
2365 else if (slot % 11 != 0)
2366 {
2367 strcpy(stemp, " ");
2368 memcpy(stemp, saveFiles[slot-1].name, strlen(saveFiles[slot-1].name));
2369 temp = strlen(stemp);
2370 while (stemp[temp-1] == ' ' && --temp);
2371
2372 flash = 8 * 16 + 10;
2373
2374 wait_noinput(false, true, false);
2375
2376 JE_barShade(VGAScreen, 65, 55, 255, 155);
2377
2378 bool quit = false;
2379 while (!quit)
2380 {
2381 service_SDL_events(true);
2382
2383 blit_sprite(VGAScreen, 50, 50, OPTION_SHAPES, 35); // message box
2384
2385 JE_textShade(VGAScreen, 60, 55, miscText[1-1], 11, 4, DARKEN);
2386 JE_textShade(VGAScreen, 70, 70, levelName, 11, 4, DARKEN);
2387
2388 do
2389 {
2390 flash = (flash == 8 * 16 + 10) ? 8 * 16 + 2 : 8 * 16 + 10;
2391 temp3 = (temp3 == 6) ? 2 : 6;
2392
2393 strcpy(tempStr, miscText[2-1]);
2394 strncat(tempStr, stemp, temp);
2395 JE_outText(VGAScreen, 65, 89, tempStr, 8, 3);
2396 tempW = 65 + JE_textWidth(tempStr, TINY_FONT);
2397 JE_barShade(VGAScreen, tempW + 2, 90, tempW + 6, 95);
2398 fill_rectangle_xy(VGAScreen, tempW + 1, 89, tempW + 5, 94, flash);
2399
2400 for (int i = 0; i < 14; i++)
2401 {
2402 setjasondelay(1);
2403
2404 JE_mouseStart();
2405 JE_showVGA();
2406 JE_mouseReplace();
2407
2408 push_joysticks_as_keyboard();
2409 service_wait_delay();
2410
2411 if (newkey || newmouse)
2412 break;
2413 }
2414
2415 }
2416 while (!newkey && !newmouse);
2417
2418 if (mouseButton > 0)
2419 {
2420 if (mouseX > 56 && mouseX < 142 && mouseY > 123 && mouseY < 149)
2421 {
2422 quit = true;
2423 JE_saveGame(slot, stemp);
2424 JE_playSampleNum(S_SELECT);
2425 }
2426 else if (mouseX > 151 && mouseX < 237 && mouseY > 123 && mouseY < 149)
2427 {
2428 quit = true;
2429 JE_playSampleNum(S_SPRING);
2430 }
2431 }
2432 else if (newkey)
2433 {
2434 bool validkey = false;
2435 lastkey_char = toupper(lastkey_char);
2436 switch (lastkey_char)
2437 {
2438 case ' ':
2439 case '-':
2440 case '.':
2441 case ',':
2442 case ':':
2443 case '!':
2444 case '?':
2445 case '#':
2446 case '@':
2447 case '$':
2448 case '%':
2449 case '*':
2450 case '(':
2451 case ')':
2452 case '/':
2453 case '=':
2454 case '+':
2455 case '<':
2456 case '>':
2457 case ';':
2458 case '"':
2459 case '\'':
2460 validkey = true;
2461 default:
2462 if (temp < 14 && (validkey || (lastkey_char >= 'A' && lastkey_char <= 'Z') || (lastkey_char >= '0' && lastkey_char <= '9')))
2463 {
2464 JE_playSampleNum(S_CURSOR);
2465 stemp[temp] = lastkey_char;
2466 temp++;
2467 }
2468 break;
2469 case SDLK_BACKSPACE:
2470 case SDLK_DELETE:
2471 if (temp)
2472 {
2473 temp--;
2474 stemp[temp] = ' ';
2475 JE_playSampleNum(S_CLICK);
2476 }
2477 break;
2478 case SDLK_ESCAPE:
2479 quit = true;
2480 JE_playSampleNum(S_SPRING);
2481 break;
2482 case SDLK_RETURN:
2483 quit = true;
2484 JE_saveGame(slot, stemp);
2485 JE_playSampleNum(S_SELECT);
2486 break;
2487 }
2488
2489 }
2490 }
2491 }
2492
2493 wait_noinput(false, true, false);
2494 }
2495
JE_inGameDisplays(void)2496 void JE_inGameDisplays( void )
2497 {
2498 char stemp[21];
2499 char tempstr[256];
2500
2501 for (uint i = 0; i < ((twoPlayerMode && !galagaMode) ? 2 : 1); ++i)
2502 {
2503 snprintf(tempstr, sizeof(tempstr), "%lu", player[i].cash);
2504 JE_textShade(VGAScreen, 30 + 200 * i, 175, tempstr, 2, 4, FULL_SHADE);
2505 }
2506
2507 /*Special Weapon?*/
2508 if (player[0].items.special > 0)
2509 blit_sprite2x2(VGAScreen, 25, 1, eShapes[5], special[player[0].items.special].itemgraphic);
2510
2511 /*Lives Left*/
2512 if (onePlayerAction || twoPlayerMode)
2513 {
2514 for (int temp = 0; temp < (onePlayerAction ? 1 : 2); temp++)
2515 {
2516 const uint extra_lives = *player[temp].lives - 1;
2517
2518 int y = (temp == 0 && player[0].items.special > 0) ? 35 : 15;
2519 tempW = (temp == 0) ? 30: 270;
2520
2521 if (extra_lives >= 5)
2522 {
2523 blit_sprite2(VGAScreen, tempW, y, shapes9, 285);
2524 tempW = (temp == 0) ? 45 : 250;
2525 sprintf(tempstr, "%d", extra_lives);
2526 JE_textShade(VGAScreen, tempW, y + 3, tempstr, 15, 1, FULL_SHADE);
2527 }
2528 else if (extra_lives >= 1)
2529 {
2530 for (uint i = 0; i < extra_lives; ++i)
2531 {
2532 blit_sprite2(VGAScreen, tempW, y, shapes9, 285);
2533
2534 tempW += (temp == 0) ? 12 : -12;
2535 }
2536 }
2537
2538 strcpy(stemp, (temp == 0) ? miscText[49-1] : miscText[50-1]);
2539 if (isNetworkGame)
2540 {
2541 strcpy(stemp, JE_getName(temp+1));
2542 }
2543
2544 tempW = (temp == 0) ? 28 : (285 - JE_textWidth(stemp, TINY_FONT));
2545 JE_textShade(VGAScreen, tempW, y - 7, stemp, 2, 6, FULL_SHADE);
2546 }
2547 }
2548
2549 /*Super Bombs!!*/
2550 for (uint i = 0; i < COUNTOF(player); ++i)
2551 {
2552 int x = (i == 0) ? 30 : 270;
2553
2554 for (uint j = player[i].superbombs; j > 0; --j)
2555 {
2556 blit_sprite2(VGAScreen, x, 160, shapes9, 304);
2557 x += (i == 0) ? 12 : -12;
2558 }
2559 }
2560
2561 if (youAreCheating)
2562 {
2563 JE_outText(VGAScreen, 90, 170, "Cheaters always prosper.", 3, 4);
2564 }
2565 }
2566
JE_mainKeyboardInput(void)2567 void JE_mainKeyboardInput( void )
2568 {
2569 JE_gammaCheck();
2570
2571 /* { Network Request Commands } */
2572
2573 if (!isNetworkGame)
2574 {
2575 /* { Edited Ships } for Player 1 */
2576 if (extraAvail && keysactive[SDLK_TAB] && !isNetworkGame && !superTyrian)
2577 {
2578 for (x = SDLK_0; x <= SDLK_9; x++)
2579 {
2580 if (keysactive[x])
2581 {
2582 int z = x == SDLK_0 ? 10 : x - SDLK_0;
2583 player[0].items.ship = 90 + z; /*Ships*/
2584 z = (z - 1) * 15;
2585 player[0].items.weapon[FRONT_WEAPON].id = extraShips[z + 1];
2586 player[0].items.weapon[REAR_WEAPON].id = extraShips[z + 2];
2587 player[0].items.special = extraShips[z + 3];
2588 player[0].items.sidekick[LEFT_SIDEKICK] = extraShips[z + 4];
2589 player[0].items.sidekick[RIGHT_SIDEKICK] = extraShips[z + 5];
2590 player[0].items.generator = extraShips[z + 6];
2591 /*Armor*/
2592 player[0].items.shield = extraShips[z + 8];
2593 memset(shotMultiPos, 0, sizeof(shotMultiPos));
2594
2595 if (player[0].weapon_mode > JE_portConfigs())
2596 player[0].weapon_mode = 1;
2597
2598 tempW = player[0].armor;
2599 JE_getShipInfo();
2600 if (player[0].armor > tempW && editShip1)
2601 player[0].armor = tempW;
2602 else
2603 editShip1 = true;
2604
2605 SDL_Surface *temp_surface = VGAScreen;
2606 VGAScreen = VGAScreenSeg;
2607 JE_wipeShieldArmorBars();
2608 JE_drawArmor();
2609 JE_drawShield();
2610 VGAScreen = temp_surface;
2611 JE_drawOptions();
2612
2613 keysactive[x] = false;
2614 }
2615 }
2616 }
2617
2618 /* for Player 2 */
2619 if (extraAvail && keysactive[SDLK_CAPSLOCK] && !isNetworkGame && !superTyrian)
2620 {
2621 for (x = SDLK_0; x <= SDLK_9; x++)
2622 {
2623 if (keysactive[x])
2624 {
2625 int z = x == SDLK_0 ? 10 : x - SDLK_0;
2626 player[1].items.ship = 90 + z;
2627 z = (z - 1) * 15;
2628 player[1].items.weapon[FRONT_WEAPON].id = extraShips[z + 1];
2629 player[1].items.weapon[REAR_WEAPON].id = extraShips[z + 2];
2630 player[1].items.special = extraShips[z + 3];
2631 player[1].items.sidekick[LEFT_SIDEKICK] = extraShips[z + 4];
2632 player[1].items.sidekick[RIGHT_SIDEKICK] = extraShips[z + 5];
2633 player[1].items.generator = extraShips[z + 6];
2634 /*Armor*/
2635 player[1].items.shield = extraShips[z + 8];
2636 memset(shotMultiPos, 0, sizeof(shotMultiPos));
2637
2638 if (player[1].weapon_mode > JE_portConfigs())
2639 player[1].weapon_mode = 1;
2640
2641 tempW = player[1].armor;
2642 JE_getShipInfo();
2643 if (player[1].armor > tempW && editShip2)
2644 player[1].armor = tempW;
2645 else
2646 editShip2 = true;
2647
2648 SDL_Surface *temp_surface = VGAScreen;
2649 VGAScreen = VGAScreenSeg;
2650 JE_wipeShieldArmorBars();
2651 JE_drawArmor();
2652 JE_drawShield();
2653 VGAScreen = temp_surface;
2654 JE_drawOptions();
2655
2656 keysactive[x] = false;
2657 }
2658 }
2659 }
2660 }
2661
2662 /* { In-Game Help } */
2663 if (keysactive[SDLK_F1])
2664 {
2665 if (isNetworkGame)
2666 {
2667 helpRequest = true;
2668 } else {
2669 JE_inGameHelp();
2670 skipStarShowVGA = true;
2671 }
2672 }
2673
2674 /* {!Activate Nort Ship!} */
2675 if (keysactive[SDLK_F2] && keysactive[SDLK_F4] && keysactive[SDLK_F6] && keysactive[SDLK_F7] &&
2676 keysactive[SDLK_F9] && keysactive[SDLK_BACKSLASH] && keysactive[SDLK_SLASH])
2677 {
2678 if (isNetworkGame)
2679 {
2680 nortShipRequest = true;
2681 }
2682 else
2683 {
2684 player[0].items.ship = 12; // Nort Ship
2685 player[0].items.special = 13; // Astral Zone
2686 player[0].items.weapon[FRONT_WEAPON].id = 36; // NortShip Super Pulse
2687 player[0].items.weapon[REAR_WEAPON].id = 37; // NortShip Spreader
2688 shipGr = 1;
2689 }
2690 }
2691
2692 /* {Cheating} */
2693 if (!isNetworkGame && !twoPlayerMode && !superTyrian && superArcadeMode == SA_NONE)
2694 {
2695 if (keysactive[SDLK_F2] && keysactive[SDLK_F3] && keysactive[SDLK_F6])
2696 {
2697 youAreCheating = !youAreCheating;
2698 keysactive[SDLK_F2] = false;
2699 }
2700
2701 if (keysactive[SDLK_F2] && keysactive[SDLK_F3] && (keysactive[SDLK_F4] || keysactive[SDLK_F5]))
2702 {
2703 for (uint i = 0; i < COUNTOF(player); ++i)
2704 player[i].armor = 0;
2705
2706 youAreCheating = !youAreCheating;
2707 JE_drawTextWindow(miscText[63-1]);
2708 }
2709
2710 if (constantPlay && keysactive[SDLK_c])
2711 {
2712 youAreCheating = !youAreCheating;
2713 keysactive[SDLK_c] = false;
2714 }
2715 }
2716
2717 if (superTyrian)
2718 {
2719 youAreCheating = false;
2720 }
2721
2722 /* {Personal Commands} */
2723
2724 /* {DEBUG} */
2725 if (keysactive[SDLK_F10] && keysactive[SDLK_BACKSPACE])
2726 {
2727 keysactive[SDLK_F10] = false;
2728 debug = !debug;
2729
2730 debugHist = 1;
2731 debugHistCount = 1;
2732
2733 /* YKS: clock ticks since midnight replaced by SDL_GetTicks */
2734 lastDebugTime = SDL_GetTicks();
2735 }
2736
2737 /* {CHEAT-SKIP LEVEL} */
2738 if (keysactive[SDLK_F2] && keysactive[SDLK_F6] && (keysactive[SDLK_F7] || keysactive[SDLK_F8]) && !keysactive[SDLK_F9]
2739 && !superTyrian && superArcadeMode == SA_NONE)
2740 {
2741 if (isNetworkGame)
2742 {
2743 skipLevelRequest = true;
2744 } else {
2745 levelTimer = true;
2746 levelTimerCountdown = 0;
2747 endLevel = true;
2748 levelEnd = 40;
2749 }
2750 }
2751
2752 /* pause game */
2753 pause_pressed = pause_pressed || keysactive[SDLK_p];
2754
2755 /* in-game setup */
2756 ingamemenu_pressed = ingamemenu_pressed || keysactive[SDLK_ESCAPE];
2757
2758 if (keysactive[SDLK_BACKSPACE])
2759 {
2760 /* toggle screenshot pause */
2761 if (keysactive[SDLK_NUMLOCK])
2762 {
2763 superPause = !superPause;
2764 }
2765
2766 /* {SMOOTHIES} */
2767 if (keysactive[SDLK_F12] && keysactive[SDLK_SCROLLOCK])
2768 {
2769 for (temp = SDLK_2; temp <= SDLK_9; temp++)
2770 {
2771 if (keysactive[temp])
2772 {
2773 smoothies[temp-SDLK_2] = !smoothies[temp-SDLK_2];
2774 }
2775 }
2776 if (keysactive[SDLK_0])
2777 {
2778 smoothies[8] = !smoothies[8];
2779 }
2780 } else
2781
2782 /* {CYCLE THROUGH FILTER COLORS} */
2783 if (keysactive[SDLK_MINUS])
2784 {
2785 if (levelFilter == -99)
2786 {
2787 levelFilter = 0;
2788 } else {
2789 levelFilter++;
2790 if (levelFilter == 16)
2791 {
2792 levelFilter = -99;
2793 }
2794 }
2795 } else
2796
2797 /* {HYPER-SPEED} */
2798 if (keysactive[SDLK_1])
2799 {
2800 fastPlay++;
2801 if (fastPlay > 2)
2802 {
2803 fastPlay = 0;
2804 }
2805 keysactive[SDLK_1] = false;
2806 JE_setNewGameSpeed();
2807 }
2808
2809 /* {IN-GAME RANDOM MUSIC SELECTION} */
2810 if (keysactive[SDLK_SCROLLOCK])
2811 {
2812 play_song(mt_rand() % MUSIC_NUM);
2813 }
2814 }
2815 }
2816
JE_pauseGame(void)2817 void JE_pauseGame( void )
2818 {
2819 JE_boolean done = false;
2820 JE_word mouseX, mouseY;
2821
2822 //tempScreenSeg = VGAScreenSeg; // sega000
2823 if (!superPause)
2824 {
2825 JE_dString(VGAScreenSeg, 120, 90, miscText[22], FONT_SHAPES);
2826
2827 VGAScreen = VGAScreenSeg;
2828 JE_showVGA();
2829 }
2830
2831 set_volume(tyrMusicVolume / 2, fxVolume);
2832
2833 #ifdef WITH_NETWORK
2834 if (isNetworkGame)
2835 {
2836 network_prepare(PACKET_GAME_PAUSE);
2837 network_send(4); // PACKET_GAME_PAUSE
2838
2839 while (true)
2840 {
2841 service_SDL_events(false);
2842
2843 if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_GAME_PAUSE)
2844 {
2845 network_update();
2846 break;
2847 }
2848
2849 network_update();
2850 network_check();
2851
2852 SDL_Delay(16);
2853 }
2854 }
2855 #endif
2856
2857 wait_noinput(false, false, true); // TODO: should up the joystick repeat temporarily instead
2858
2859 do
2860 {
2861 setjasondelay(2);
2862
2863 push_joysticks_as_keyboard();
2864 service_SDL_events(true);
2865
2866 if ((newkey && lastkey_sym != SDLK_LCTRL && lastkey_sym != SDLK_RCTRL && lastkey_sym != SDLK_LALT && lastkey_sym != SDLK_RALT)
2867 || JE_mousePosition(&mouseX, &mouseY) > 0)
2868 {
2869 #ifdef WITH_NETWORK
2870 if (isNetworkGame)
2871 {
2872 network_prepare(PACKET_WAITING);
2873 network_send(4); // PACKET_WAITING
2874 }
2875 #endif
2876 done = true;
2877 }
2878
2879 #ifdef WITH_NETWORK
2880 if (isNetworkGame)
2881 {
2882 network_check();
2883
2884 if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_WAITING)
2885 {
2886 network_check();
2887
2888 done = true;
2889 }
2890 }
2891 #endif
2892
2893 wait_delay();
2894 } while (!done);
2895
2896 #ifdef WITH_NETWORK
2897 if (isNetworkGame)
2898 {
2899 while (!network_is_sync())
2900 {
2901 service_SDL_events(false);
2902
2903 network_check();
2904 SDL_Delay(16);
2905 }
2906 }
2907 #endif
2908
2909 set_volume(tyrMusicVolume, fxVolume);
2910
2911 //skipStarShowVGA = true;
2912 }
2913
JE_playerMovement(Player * this_player,JE_byte inputDevice,JE_byte playerNum_,JE_word shipGr_,Sprite2_array * shapes9ptr_,JE_word * mouseX_,JE_word * mouseY_)2914 void JE_playerMovement( Player *this_player,
2915 JE_byte inputDevice,
2916 JE_byte playerNum_,
2917 JE_word shipGr_,
2918 Sprite2_array *shapes9ptr_,
2919 JE_word *mouseX_, JE_word *mouseY_ )
2920 {
2921 JE_integer mouseXC, mouseYC;
2922 JE_integer accelXC, accelYC;
2923
2924 if (playerNum_ == 2 || !twoPlayerMode)
2925 {
2926 tempW = weaponPort[this_player->items.weapon[REAR_WEAPON].id].opnum;
2927
2928 if (this_player->weapon_mode > tempW)
2929 this_player->weapon_mode = 1;
2930 }
2931
2932 #ifdef WITH_NETWORK
2933 if (isNetworkGame && thisPlayerNum == playerNum_)
2934 {
2935 network_state_prepare();
2936 memset(&packet_state_out[0]->data[4], 0, 10);
2937 }
2938 #endif
2939
2940 redo:
2941
2942 if (isNetworkGame)
2943 {
2944 inputDevice = 0;
2945 }
2946
2947 mouseXC = 0;
2948 mouseYC = 0;
2949 accelXC = 0;
2950 accelYC = 0;
2951
2952 bool link_gun_analog = false;
2953 float link_gun_angle = 0;
2954
2955 /* Draw Player */
2956 if (!this_player->is_alive)
2957 {
2958 if (this_player->exploding_ticks > 0)
2959 {
2960 --this_player->exploding_ticks;
2961
2962 if (levelEndFxWait > 0)
2963 {
2964 levelEndFxWait--;
2965 }
2966 else
2967 {
2968 levelEndFxWait = (mt_rand() % 6) + 3;
2969 if ((mt_rand() % 3) == 1)
2970 soundQueue[6] = S_EXPLOSION_9;
2971 else
2972 soundQueue[5] = S_EXPLOSION_11;
2973 }
2974
2975 int explosion_x = this_player->x + (mt_rand() % 32) - 16;
2976 int explosion_y = this_player->y + (mt_rand() % 32) - 16;
2977 JE_setupExplosionLarge(false, 0, explosion_x, explosion_y + 7);
2978 JE_setupExplosionLarge(false, 0, this_player->x, this_player->y + 7);
2979
2980 if (levelEnd > 0)
2981 levelEnd--;
2982 }
2983 else
2984 {
2985 if (twoPlayerMode || onePlayerAction) // if arcade mode
2986 {
2987 if (*this_player->lives > 1) // respawn if any extra lives
2988 {
2989 --(*this_player->lives);
2990
2991 reallyEndLevel = false;
2992 shotMultiPos[playerNum_-1] = 0;
2993 calc_purple_balls_needed(this_player);
2994 twoPlayerLinked = false;
2995 if (galagaMode)
2996 twoPlayerMode = false;
2997 this_player->y = 160;
2998 this_player->invulnerable_ticks = 100;
2999 this_player->is_alive = true;
3000 endLevel = false;
3001
3002 if (galagaMode || episodeNum == 4)
3003 this_player->armor = this_player->initial_armor;
3004 else
3005 this_player->armor = this_player->initial_armor / 2;
3006
3007 if (galagaMode)
3008 this_player->shield = 0;
3009 else
3010 this_player->shield = this_player->shield_max / 2;
3011
3012 VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
3013 JE_drawArmor();
3014 JE_drawShield();
3015 VGAScreen = game_screen; /* side-effect of game_screen */
3016 goto redo;
3017 }
3018 else
3019 {
3020 if (galagaMode)
3021 twoPlayerMode = false;
3022 if (allPlayersGone && isNetworkGame)
3023 reallyEndLevel = true;
3024 }
3025
3026 }
3027 }
3028 }
3029 else if (constantDie)
3030 {
3031 // finished exploding? start dying again
3032 if (this_player->exploding_ticks == 0)
3033 {
3034 this_player->shield = 0;
3035
3036 if (this_player->armor > 0)
3037 {
3038 --this_player->armor;
3039 }
3040 else
3041 {
3042 this_player->is_alive = false;
3043 this_player->exploding_ticks = 60;
3044 levelEnd = 40;
3045 }
3046
3047 JE_wipeShieldArmorBars();
3048 VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
3049 JE_drawArmor();
3050 VGAScreen = game_screen; /* side-effect of game_screen */
3051
3052 // as if instant death weren't enough, player also gets infinite lives in order to enjoy an infinite number of deaths -_-
3053 if (*player[0].lives < 11)
3054 ++(*player[0].lives);
3055 }
3056 }
3057
3058
3059 if (!this_player->is_alive)
3060 {
3061 explosionFollowAmountX = explosionFollowAmountY = 0;
3062 return;
3063 }
3064
3065 if (!endLevel)
3066 {
3067 *mouseX_ = this_player->x;
3068 *mouseY_ = this_player->y;
3069 button[1-1] = false;
3070 button[2-1] = false;
3071 button[3-1] = false;
3072 button[4-1] = false;
3073
3074 /* --- Movement Routine Beginning --- */
3075
3076 if (!isNetworkGame || playerNum_ == thisPlayerNum)
3077 {
3078 if (endLevel)
3079 {
3080 this_player->y -= 2;
3081 }
3082 else
3083 {
3084 if (record_demo || play_demo)
3085 inputDevice = 1; // keyboard is required device for demo recording
3086
3087 // demo playback input
3088 if (play_demo)
3089 {
3090 if (!replay_demo_keys())
3091 {
3092 endLevel = true;
3093 levelEnd = 40;
3094 }
3095 }
3096
3097 /* joystick input */
3098 if ((inputDevice == 0 || inputDevice >= 3) && joysticks > 0)
3099 {
3100 int j = inputDevice == 0 ? 0 : inputDevice - 3;
3101 int j_max = inputDevice == 0 ? joysticks : inputDevice - 3 + 1;
3102 for (; j < j_max; j++)
3103 {
3104 poll_joystick(j);
3105
3106 if (joystick[j].analog)
3107 {
3108 mouseXC += joystick_axis_reduce(j, joystick[j].x);
3109 mouseYC += joystick_axis_reduce(j, joystick[j].y);
3110
3111 link_gun_analog = joystick_analog_angle(j, &link_gun_angle);
3112 }
3113 else
3114 {
3115 this_player->x += (joystick[j].direction[3] ? -CURRENT_KEY_SPEED : 0) + (joystick[j].direction[1] ? CURRENT_KEY_SPEED : 0);
3116 this_player->y += (joystick[j].direction[0] ? -CURRENT_KEY_SPEED : 0) + (joystick[j].direction[2] ? CURRENT_KEY_SPEED : 0);
3117 }
3118
3119 button[0] |= joystick[j].action[0];
3120 button[1] |= joystick[j].action[2];
3121 button[2] |= joystick[j].action[3];
3122 button[3] |= joystick[j].action_pressed[1];
3123
3124 ingamemenu_pressed |= joystick[j].action_pressed[4];
3125 pause_pressed |= joystick[j].action_pressed[5];
3126 }
3127 }
3128
3129 service_SDL_events(false);
3130
3131 /* mouse input */
3132 if ((inputDevice == 0 || inputDevice == 2) && has_mouse)
3133 {
3134 button[0] |= mouse_pressed[0];
3135 button[1] |= mouse_pressed[1];
3136 button[2] |= mouse_has_three_buttons ? mouse_pressed[2] : mouse_pressed[1];
3137
3138 if (input_grab_enabled)
3139 {
3140 mouseXC += mouse_x - 159;
3141 mouseYC += mouse_y - 100;
3142 }
3143
3144 if ((!isNetworkGame || playerNum_ == thisPlayerNum)
3145 && (!galagaMode || (playerNum_ == 2 || !twoPlayerMode || player[1].exploding_ticks > 0)))
3146 {
3147 set_mouse_position(159, 100);
3148 }
3149 }
3150
3151 /* keyboard input */
3152 if ((inputDevice == 0 || inputDevice == 1) && !play_demo)
3153 {
3154 if (keysactive[keySettings[0]])
3155 this_player->y -= CURRENT_KEY_SPEED;
3156 if (keysactive[keySettings[1]])
3157 this_player->y += CURRENT_KEY_SPEED;
3158
3159 if (keysactive[keySettings[2]])
3160 this_player->x -= CURRENT_KEY_SPEED;
3161 if (keysactive[keySettings[3]])
3162 this_player->x += CURRENT_KEY_SPEED;
3163
3164 button[0] = button[0] || keysactive[keySettings[4]];
3165 button[3] = button[3] || keysactive[keySettings[5]];
3166 button[1] = button[1] || keysactive[keySettings[6]];
3167 button[2] = button[2] || keysactive[keySettings[7]];
3168
3169 if (constantPlay)
3170 {
3171 for (unsigned int i = 0; i < 4; i++)
3172 button[i] = true;
3173
3174 ++this_player->y;
3175 this_player->x += constantLastX;
3176 }
3177
3178 // TODO: check if demo recording still works
3179 if (record_demo)
3180 {
3181 bool new_input = false;
3182
3183 for (unsigned int i = 0; i < 8; i++)
3184 {
3185 bool temp = demo_keys & (1 << i);
3186 if (temp != keysactive[keySettings[i]])
3187 new_input = true;
3188 }
3189
3190 demo_keys_wait++;
3191
3192 if (new_input)
3193 {
3194 demo_keys_wait = SDL_Swap16(demo_keys_wait);
3195 efwrite(&demo_keys_wait, sizeof(Uint16), 1, demo_file);
3196
3197 demo_keys = 0;
3198 for (unsigned int i = 0; i < 8; i++)
3199 demo_keys |= keysactive[keySettings[i]] ? (1 << i) : 0;
3200
3201 fputc(demo_keys, demo_file);
3202
3203 demo_keys_wait = 0;
3204 }
3205 }
3206 }
3207
3208 if (smoothies[9-1])
3209 {
3210 *mouseY_ = this_player->y - (*mouseY_ - this_player->y);
3211 mouseYC = -mouseYC;
3212 }
3213
3214 accelXC += this_player->x - *mouseX_;
3215 accelYC += this_player->y - *mouseY_;
3216
3217 if (mouseXC > 30)
3218 mouseXC = 30;
3219 else if (mouseXC < -30)
3220 mouseXC = -30;
3221 if (mouseYC > 30)
3222 mouseYC = 30;
3223 else if (mouseYC < -30)
3224 mouseYC = -30;
3225
3226 if (mouseXC > 0)
3227 this_player->x += (mouseXC + 3) / 4;
3228 else if (mouseXC < 0)
3229 this_player->x += (mouseXC - 3) / 4;
3230 if (mouseYC > 0)
3231 this_player->y += (mouseYC + 3) / 4;
3232 else if (mouseYC < 0)
3233 this_player->y += (mouseYC - 3) / 4;
3234
3235 if (mouseXC > 3)
3236 accelXC++;
3237 else if (mouseXC < -2)
3238 accelXC--;
3239 if (mouseYC > 2)
3240 accelYC++;
3241 else if (mouseYC < -2)
3242 accelYC--;
3243
3244 } /*endLevel*/
3245
3246 #ifdef WITH_NETWORK
3247 if (isNetworkGame && playerNum_ == thisPlayerNum)
3248 {
3249 Uint16 buttons = 0;
3250 for (int i = 4 - 1; i >= 0; i--)
3251 {
3252 buttons <<= 1;
3253 buttons |= button[i];
3254 }
3255
3256 SDLNet_Write16(this_player->x - *mouseX_, &packet_state_out[0]->data[4]);
3257 SDLNet_Write16(this_player->y - *mouseY_, &packet_state_out[0]->data[6]);
3258 SDLNet_Write16(accelXC, &packet_state_out[0]->data[8]);
3259 SDLNet_Write16(accelYC, &packet_state_out[0]->data[10]);
3260 SDLNet_Write16(buttons, &packet_state_out[0]->data[12]);
3261
3262 this_player->x = *mouseX_;
3263 this_player->y = *mouseY_;
3264
3265 button[0] = false;
3266 button[1] = false;
3267 button[2] = false;
3268 button[3] = false;
3269
3270 accelXC = 0;
3271 accelYC = 0;
3272 }
3273 #endif
3274 } /*isNetworkGame*/
3275
3276 /* --- Movement Routine Ending --- */
3277
3278 moveOk = true;
3279
3280 #ifdef WITH_NETWORK
3281 if (isNetworkGame && !network_state_is_reset())
3282 {
3283 if (playerNum_ != thisPlayerNum)
3284 {
3285 if (thisPlayerNum == 2)
3286 difficultyLevel = SDLNet_Read16(&packet_state_in[0]->data[16]);
3287
3288 Uint16 buttons = SDLNet_Read16(&packet_state_in[0]->data[12]);
3289 for (int i = 0; i < 4; i++)
3290 {
3291 button[i] = buttons & 1;
3292 buttons >>= 1;
3293 }
3294
3295 this_player->x += (Sint16)SDLNet_Read16(&packet_state_in[0]->data[4]);
3296 this_player->y += (Sint16)SDLNet_Read16(&packet_state_in[0]->data[6]);
3297 accelXC = (Sint16)SDLNet_Read16(&packet_state_in[0]->data[8]);
3298 accelYC = (Sint16)SDLNet_Read16(&packet_state_in[0]->data[10]);
3299 }
3300 else
3301 {
3302 Uint16 buttons = SDLNet_Read16(&packet_state_out[network_delay]->data[12]);
3303 for (int i = 0; i < 4; i++)
3304 {
3305 button[i] = buttons & 1;
3306 buttons >>= 1;
3307 }
3308
3309 this_player->x += (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[4]);
3310 this_player->y += (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[6]);
3311 accelXC = (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[8]);
3312 accelYC = (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[10]);
3313 }
3314 }
3315 #endif
3316
3317 /*Street-Fighter codes*/
3318 JE_SFCodes(playerNum_, this_player->x, this_player->y, *mouseX_, *mouseY_);
3319
3320 if (moveOk)
3321 {
3322 /* END OF MOVEMENT ROUTINES */
3323
3324 /*Linking Routines*/
3325
3326 if (twoPlayerMode && !twoPlayerLinked && this_player->x == *mouseX_ && this_player->y == *mouseY_
3327 && abs(player[0].x - player[1].x) < 8 && abs(player[0].y - player[1].y) < 8
3328 && player[0].is_alive && player[1].is_alive && !galagaMode)
3329 {
3330 twoPlayerLinked = true;
3331 }
3332
3333 if (playerNum_ == 1 && (button[3-1] || button[2-1]) && !galagaMode)
3334 twoPlayerLinked = false;
3335
3336 if (twoPlayerMode && twoPlayerLinked && playerNum_ == 2
3337 && (this_player->x != *mouseX_ || this_player->y != *mouseY_))
3338 {
3339 if (button[0])
3340 {
3341 if (link_gun_analog)
3342 {
3343 linkGunDirec = link_gun_angle;
3344 }
3345 else
3346 {
3347 JE_real tempR;
3348
3349 if (abs(this_player->x - *mouseX_) > abs(this_player->y - *mouseY_))
3350 tempR = (this_player->x - *mouseX_ > 0) ? M_PI_2 : (M_PI + M_PI_2);
3351 else
3352 tempR = (this_player->y - *mouseY_ > 0) ? 0 : M_PI;
3353
3354 if (fabsf(linkGunDirec - tempR) < 0.3f)
3355 linkGunDirec = tempR;
3356 else if (linkGunDirec < tempR && linkGunDirec - tempR > -3.24f)
3357 linkGunDirec += 0.2f;
3358 else if (linkGunDirec - tempR < M_PI)
3359 linkGunDirec -= 0.2f;
3360 else
3361 linkGunDirec += 0.2f;
3362 }
3363
3364 if (linkGunDirec >= (2 * M_PI))
3365 linkGunDirec -= (2 * M_PI);
3366 else if (linkGunDirec < 0)
3367 linkGunDirec += (2 * M_PI);
3368 }
3369 else if (!galagaMode)
3370 {
3371 twoPlayerLinked = false;
3372 }
3373 }
3374 }
3375 }
3376
3377 if (levelEnd > 0 && all_players_dead())
3378 reallyEndLevel = true;
3379
3380 /* End Level Fade-Out */
3381 if (this_player->is_alive && endLevel)
3382 {
3383 if (levelEnd == 0)
3384 {
3385 reallyEndLevel = true;
3386 }
3387 else
3388 {
3389 this_player->y -= levelEndWarp;
3390 if (this_player->y < -200)
3391 reallyEndLevel = true;
3392
3393 int trail_spacing = 1;
3394 int trail_y = this_player->y;
3395 int num_trails = abs(41 - levelEnd);
3396 if (num_trails > 20)
3397 num_trails = 20;
3398
3399 for (int i = 0; i < num_trails; i++)
3400 {
3401 trail_y += trail_spacing;
3402 trail_spacing++;
3403 }
3404
3405 for (int i = 1; i < num_trails; i++)
3406 {
3407 trail_y -= trail_spacing;
3408 trail_spacing--;
3409
3410 if (trail_y > 0 && trail_y < 170)
3411 {
3412 if (shipGr_ == 0)
3413 {
3414 blit_sprite2x2(VGAScreen, this_player->x - 17, trail_y - 7, *shapes9ptr_, 13);
3415 blit_sprite2x2(VGAScreen, this_player->x + 7 , trail_y - 7, *shapes9ptr_, 51);
3416 }
3417 else if (shipGr_ == 1)
3418 {
3419 blit_sprite2x2(VGAScreen, this_player->x - 17, trail_y - 7, *shapes9ptr_, 220);
3420 blit_sprite2x2(VGAScreen, this_player->x + 7 , trail_y - 7, *shapes9ptr_, 222);
3421 }
3422 else
3423 {
3424 blit_sprite2x2(VGAScreen, this_player->x - 5, trail_y - 7, *shapes9ptr_, shipGr_);
3425 }
3426 }
3427 }
3428 }
3429 }
3430
3431 if (play_demo)
3432 JE_dString(VGAScreen, 115, 10, miscText[7], SMALL_FONT_SHAPES); // insert coin
3433
3434 if (this_player->is_alive && !endLevel)
3435 {
3436 if (!twoPlayerLinked || playerNum_ < 2)
3437 {
3438 if (!twoPlayerMode || shipGr2 != 0) // if not dragonwing
3439 {
3440 if (this_player->sidekick[LEFT_SIDEKICK].style == 0)
3441 {
3442 this_player->sidekick[LEFT_SIDEKICK].x = *mouseX_ - 14;
3443 this_player->sidekick[LEFT_SIDEKICK].y = *mouseY_;
3444 }
3445
3446 if (this_player->sidekick[RIGHT_SIDEKICK].style == 0)
3447 {
3448 this_player->sidekick[RIGHT_SIDEKICK].x = *mouseX_ + 16;
3449 this_player->sidekick[RIGHT_SIDEKICK].y = *mouseY_;
3450 }
3451 }
3452
3453 if (this_player->x_friction_ticks > 0)
3454 {
3455 --this_player->x_friction_ticks;
3456 }
3457 else
3458 {
3459 this_player->x_friction_ticks = 1;
3460
3461 if (this_player->x_velocity < 0)
3462 ++this_player->x_velocity;
3463 else if (this_player->x_velocity > 0)
3464 --this_player->x_velocity;
3465 }
3466
3467 if (this_player->y_friction_ticks > 0)
3468 {
3469 --this_player->y_friction_ticks;
3470 }
3471 else
3472 {
3473 this_player->y_friction_ticks = 2;
3474
3475 if (this_player->y_velocity < 0)
3476 ++this_player->y_velocity;
3477 else if (this_player->y_velocity > 0)
3478 --this_player->y_velocity;
3479 }
3480
3481 this_player->x_velocity += accelXC;
3482 this_player->y_velocity += accelYC;
3483
3484 this_player->x_velocity = MIN(MAX(-4, this_player->x_velocity), 4);
3485 this_player->y_velocity = MIN(MAX(-4, this_player->y_velocity), 4);
3486
3487 this_player->x += this_player->x_velocity;
3488 this_player->y += this_player->y_velocity;
3489
3490 // if player moved, add new ship x, y history entry
3491 if (this_player->x - *mouseX_ != 0 || this_player->y - *mouseY_ != 0)
3492 {
3493 for (uint i = 1; i < COUNTOF(player->old_x); ++i)
3494 {
3495 this_player->old_x[i - 1] = this_player->old_x[i];
3496 this_player->old_y[i - 1] = this_player->old_y[i];
3497 }
3498 this_player->old_x[COUNTOF(player->old_x) - 1] = this_player->x;
3499 this_player->old_y[COUNTOF(player->old_x) - 1] = this_player->y;
3500 }
3501 }
3502 else /*twoPlayerLinked*/
3503 {
3504 if (shipGr_ == 0)
3505 this_player->x = player[0].x - 1;
3506 else
3507 this_player->x = player[0].x;
3508 this_player->y = player[0].y + 8;
3509
3510 this_player->x_velocity = player[0].x_velocity;
3511 this_player->y_velocity = 4;
3512
3513 // turret direction marker/shield
3514 shotMultiPos[SHOT_MISC] = 0;
3515 b = player_shot_create(0, SHOT_MISC, this_player->x + 1 + roundf(sinf(linkGunDirec + 0.2f) * 26), this_player->y + roundf(cosf(linkGunDirec + 0.2f) * 26), *mouseX_, *mouseY_, 148, playerNum_);
3516 shotMultiPos[SHOT_MISC] = 0;
3517 b = player_shot_create(0, SHOT_MISC, this_player->x + 1 + roundf(sinf(linkGunDirec - 0.2f) * 26), this_player->y + roundf(cosf(linkGunDirec - 0.2f) * 26), *mouseX_, *mouseY_, 148, playerNum_);
3518 shotMultiPos[SHOT_MISC] = 0;
3519 b = player_shot_create(0, SHOT_MISC, this_player->x + 1 + roundf(sinf(linkGunDirec) * 26), this_player->y + roundf(cosf(linkGunDirec) * 26), *mouseX_, *mouseY_, 147, playerNum_);
3520
3521 if (shotRepeat[SHOT_REAR] > 0)
3522 {
3523 --shotRepeat[SHOT_REAR];
3524 }
3525 else if (button[1-1])
3526 {
3527 shotMultiPos[SHOT_REAR] = 0;
3528 b = player_shot_create(0, SHOT_REAR, this_player->x + 1 + roundf(sinf(linkGunDirec) * 20), this_player->y + roundf(cosf(linkGunDirec) * 20), *mouseX_, *mouseY_, linkGunWeapons[this_player->items.weapon[REAR_WEAPON].id-1], playerNum_);
3529 player_shot_set_direction(b, this_player->items.weapon[REAR_WEAPON].id, linkGunDirec);
3530 }
3531 }
3532 }
3533
3534 if (!endLevel)
3535 {
3536 if (this_player->x > 256)
3537 {
3538 this_player->x = 256;
3539 constantLastX = -constantLastX;
3540 }
3541 if (this_player->x < 40)
3542 {
3543 this_player->x = 40;
3544 constantLastX = -constantLastX;
3545 }
3546
3547 if (isNetworkGame && playerNum_ == 1)
3548 {
3549 if (this_player->y > 154)
3550 this_player->y = 154;
3551 }
3552 else
3553 {
3554 if (this_player->y > 160)
3555 this_player->y = 160;
3556 }
3557
3558 if (this_player->y < 10)
3559 this_player->y = 10;
3560
3561 // Determines the ship banking sprite to display, depending on horizontal velocity and acceleration
3562 int ship_banking = this_player->x_velocity / 2 + (this_player->x - *mouseX_) / 6;
3563 ship_banking = MAX(-2, MIN(ship_banking, 2));
3564
3565 int ship_sprite = ship_banking * 2 + shipGr_;
3566
3567 explosionFollowAmountX = this_player->x - this_player->last_x_explosion_follow;
3568 explosionFollowAmountY = this_player->y - this_player->last_y_explosion_follow;
3569
3570 if (explosionFollowAmountY < 0)
3571 explosionFollowAmountY = 0;
3572
3573 this_player->last_x_explosion_follow = this_player->x;
3574 this_player->last_y_explosion_follow = this_player->y;
3575
3576 if (shipGr_ == 0)
3577 {
3578 if (background2)
3579 {
3580 blit_sprite2x2_darken(VGAScreen, this_player->x - 17 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite + 13);
3581 blit_sprite2x2_darken(VGAScreen, this_player->x + 7 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite + 51);
3582 if (superWild)
3583 {
3584 blit_sprite2x2_darken(VGAScreen, this_player->x - 16 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite + 13);
3585 blit_sprite2x2_darken(VGAScreen, this_player->x + 6 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite + 51);
3586 }
3587 }
3588 }
3589 else if (shipGr_ == 1)
3590 {
3591 if (background2)
3592 {
3593 blit_sprite2x2_darken(VGAScreen, this_player->x - 17 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, 220);
3594 blit_sprite2x2_darken(VGAScreen, this_player->x + 7 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, 222);
3595 }
3596 }
3597 else
3598 {
3599 if (background2)
3600 {
3601 blit_sprite2x2_darken(VGAScreen, this_player->x - 5 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite);
3602 if (superWild)
3603 {
3604 blit_sprite2x2_darken(VGAScreen, this_player->x - 4 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite);
3605 }
3606 }
3607 }
3608
3609 if (this_player->invulnerable_ticks > 0)
3610 {
3611 --this_player->invulnerable_ticks;
3612
3613 if (shipGr_ == 0)
3614 {
3615 blit_sprite2x2_blend(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, ship_sprite + 13);
3616 blit_sprite2x2_blend(VGAScreen, this_player->x + 7 , this_player->y - 7, *shapes9ptr_, ship_sprite + 51);
3617 }
3618 else if (shipGr_ == 1)
3619 {
3620 blit_sprite2x2_blend(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, 220);
3621 blit_sprite2x2_blend(VGAScreen, this_player->x + 7 , this_player->y - 7, *shapes9ptr_, 222);
3622 }
3623 else
3624 blit_sprite2x2_blend(VGAScreen, this_player->x - 5, this_player->y - 7, *shapes9ptr_, ship_sprite);
3625 }
3626 else
3627 {
3628 if (shipGr_ == 0)
3629 {
3630 blit_sprite2x2(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, ship_sprite + 13);
3631 blit_sprite2x2(VGAScreen, this_player->x + 7, this_player->y - 7, *shapes9ptr_, ship_sprite + 51);
3632 }
3633 else if (shipGr_ == 1)
3634 {
3635 blit_sprite2x2(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, 220);
3636 blit_sprite2x2(VGAScreen, this_player->x + 7, this_player->y - 7, *shapes9ptr_, 222);
3637
3638 int ship_banking;
3639 switch (ship_sprite)
3640 {
3641 case 5:
3642 blit_sprite2(VGAScreen, this_player->x - 17, this_player->y + 7, *shapes9ptr_, 40);
3643 tempW = this_player->x - 7;
3644 ship_banking = -2;
3645 break;
3646 case 3:
3647 blit_sprite2(VGAScreen, this_player->x - 17, this_player->y + 7, *shapes9ptr_, 39);
3648 tempW = this_player->x - 7;
3649 ship_banking = -1;
3650 break;
3651 case 1:
3652 ship_banking = 0;
3653 break;
3654 case -1:
3655 blit_sprite2(VGAScreen, this_player->x + 19, this_player->y + 7, *shapes9ptr_, 58);
3656 tempW = this_player->x + 9;
3657 ship_banking = 1;
3658 break;
3659 case -3:
3660 blit_sprite2(VGAScreen, this_player->x + 19, this_player->y + 7, *shapes9ptr_, 59);
3661 tempW = this_player->x + 9;
3662 ship_banking = 2;
3663 break;
3664 }
3665 if (ship_banking != 0) // NortSparks
3666 {
3667 if (shotRepeat[SHOT_NORTSPARKS] > 0)
3668 {
3669 --shotRepeat[SHOT_NORTSPARKS];
3670 }
3671 else
3672 {
3673 b = player_shot_create(0, SHOT_NORTSPARKS, tempW + (mt_rand() % 8) - 4, this_player->y + (mt_rand() % 8) - 4, *mouseX_, *mouseY_, 671, 1);
3674 shotRepeat[SHOT_NORTSPARKS] = abs(ship_banking) - 1;
3675 }
3676 }
3677 }
3678 else
3679 {
3680 blit_sprite2x2(VGAScreen, this_player->x - 5, this_player->y - 7, *shapes9ptr_, ship_sprite);
3681 }
3682 }
3683
3684 /*Options Location*/
3685 if (playerNum_ == 2 && shipGr_ == 0) // if dragonwing
3686 {
3687 if (this_player->sidekick[LEFT_SIDEKICK].style == 0)
3688 {
3689 this_player->sidekick[LEFT_SIDEKICK].x = this_player->x - 14 + ship_banking * 2;
3690 this_player->sidekick[LEFT_SIDEKICK].y = this_player->y;
3691 }
3692
3693 if (this_player->sidekick[RIGHT_SIDEKICK].style == 0)
3694 {
3695 this_player->sidekick[RIGHT_SIDEKICK].x = this_player->x + 17 + ship_banking * 2;
3696 this_player->sidekick[RIGHT_SIDEKICK].y = this_player->y;
3697 }
3698 }
3699 } // !endLevel
3700
3701 if (moveOk)
3702 {
3703 if (this_player->is_alive)
3704 {
3705 if (!endLevel)
3706 {
3707 this_player->delta_x_shot_move = this_player->x - this_player->last_x_shot_move;
3708 this_player->delta_y_shot_move = this_player->y - this_player->last_y_shot_move;
3709
3710 /* PLAYER SHOT Change */
3711 if (button[4-1])
3712 {
3713 portConfigChange = true;
3714 if (portConfigDone)
3715 {
3716 shotMultiPos[SHOT_REAR] = 0;
3717
3718 if (superArcadeMode != SA_NONE && superArcadeMode <= SA_NORTSHIPZ)
3719 {
3720 shotMultiPos[SHOT_SPECIAL] = 0;
3721 shotMultiPos[SHOT_SPECIAL2] = 0;
3722 if (player[0].items.special == SASpecialWeapon[superArcadeMode-1])
3723 {
3724 player[0].items.special = SASpecialWeaponB[superArcadeMode-1];
3725 this_player->weapon_mode = 2;
3726 }
3727 else
3728 {
3729 player[0].items.special = SASpecialWeapon[superArcadeMode-1];
3730 this_player->weapon_mode = 1;
3731 }
3732 }
3733 else if (++this_player->weapon_mode > JE_portConfigs())
3734 this_player->weapon_mode = 1;
3735
3736 JE_drawPortConfigButtons();
3737 portConfigDone = false;
3738 }
3739 }
3740
3741 /* PLAYER SHOT Creation */
3742
3743 /*SpecialShot*/
3744 if (!galagaMode)
3745 JE_doSpecialShot(playerNum_, &this_player->armor, &this_player->shield);
3746
3747 /*Normal Main Weapons*/
3748 if (!(twoPlayerLinked && playerNum_ == 2))
3749 {
3750 int min, max;
3751
3752 if (!twoPlayerMode)
3753 min = 1, max = 2;
3754 else
3755 min = max = playerNum_;
3756
3757 for (temp = min - 1; temp < max; temp++)
3758 {
3759 const uint item = this_player->items.weapon[temp].id;
3760
3761 if (item > 0)
3762 {
3763 if (shotRepeat[temp] > 0)
3764 {
3765 --shotRepeat[temp];
3766 }
3767 else if (button[1-1])
3768 {
3769 const uint item_power = galagaMode ? 0 : this_player->items.weapon[temp].power - 1,
3770 item_mode = (temp == REAR_WEAPON) ? this_player->weapon_mode - 1 : 0;
3771
3772 b = player_shot_create(item, temp, this_player->x, this_player->y, *mouseX_, *mouseY_, weaponPort[item].op[item_mode][item_power], playerNum_);
3773 }
3774 }
3775 }
3776 }
3777
3778 /*Super Charge Weapons*/
3779 if (playerNum_ == 2)
3780 {
3781
3782 if (!twoPlayerLinked)
3783 blit_sprite2(VGAScreen, this_player->x + (shipGr_ == 0) + 1, this_player->y - 13, eShapes[5], 77 + chargeLevel + chargeGr * 19);
3784
3785 if (chargeGrWait > 0)
3786 {
3787 chargeGrWait--;
3788 }
3789 else
3790 {
3791 chargeGr++;
3792 if (chargeGr == 4)
3793 chargeGr = 0;
3794 chargeGrWait = 3;
3795 }
3796
3797 if (chargeLevel > 0)
3798 {
3799 fill_rectangle_xy(VGAScreenSeg, 269, 107 + (chargeLevel - 1) * 3, 275, 108 + (chargeLevel - 1) * 3, 193);
3800 }
3801
3802 if (chargeWait > 0)
3803 {
3804 chargeWait--;
3805 }
3806 else
3807 {
3808 if (chargeLevel < chargeMax)
3809 chargeLevel++;
3810
3811 chargeWait = 28 - this_player->items.weapon[REAR_WEAPON].power * 2;
3812 if (difficultyLevel > 3)
3813 chargeWait -= 5;
3814 }
3815
3816 if (chargeLevel > 0)
3817 fill_rectangle_xy(VGAScreenSeg, 269, 107 + (chargeLevel - 1) * 3, 275, 108 + (chargeLevel - 1) * 3, 204);
3818
3819 if (shotRepeat[SHOT_P2_CHARGE] > 0)
3820 {
3821 --shotRepeat[SHOT_P2_CHARGE];
3822 }
3823 else if (button[1-1] && (!twoPlayerLinked || chargeLevel > 0))
3824 {
3825 shotMultiPos[SHOT_P2_CHARGE] = 0;
3826 b = player_shot_create(16, SHOT_P2_CHARGE, this_player->x, this_player->y, *mouseX_, *mouseY_, chargeGunWeapons[player[1].items.weapon[REAR_WEAPON].id-1] + chargeLevel, playerNum_);
3827
3828 if (chargeLevel > 0)
3829 fill_rectangle_xy(VGAScreenSeg, 269, 107 + (chargeLevel - 1) * 3, 275, 108 + (chargeLevel - 1) * 3, 193);
3830
3831 chargeLevel = 0;
3832 chargeWait = 30 - this_player->items.weapon[REAR_WEAPON].power * 2;
3833 }
3834 }
3835
3836 /*SUPER BOMB*/
3837 temp = playerNum_;
3838 if (temp == 0)
3839 temp = 1; /*Get whether player 1 or 2*/
3840
3841 if (player[temp-1].superbombs > 0)
3842 {
3843 if (shotRepeat[SHOT_P1_SUPERBOMB + temp-1] > 0)
3844 {
3845 --shotRepeat[SHOT_P1_SUPERBOMB + temp-1];
3846 }
3847 else if (button[3-1] || button[2-1])
3848 {
3849 --player[temp-1].superbombs;
3850 shotMultiPos[SHOT_P1_SUPERBOMB + temp-1] = 0;
3851 b = player_shot_create(16, SHOT_P1_SUPERBOMB + temp-1, this_player->x, this_player->y, *mouseX_, *mouseY_, 535, playerNum_);
3852 }
3853 }
3854
3855 // sidekicks
3856
3857 if (this_player->sidekick[LEFT_SIDEKICK].style == 4 && this_player->sidekick[RIGHT_SIDEKICK].style == 4)
3858 optionSatelliteRotate += 0.2f;
3859 else if (this_player->sidekick[LEFT_SIDEKICK].style == 4 || this_player->sidekick[RIGHT_SIDEKICK].style == 4)
3860 optionSatelliteRotate += 0.15f;
3861
3862 switch (this_player->sidekick[LEFT_SIDEKICK].style)
3863 {
3864 case 1: // trailing
3865 case 3:
3866 this_player->sidekick[LEFT_SIDEKICK].x = this_player->old_x[COUNTOF(player->old_x) / 2 - 1];
3867 this_player->sidekick[LEFT_SIDEKICK].y = this_player->old_y[COUNTOF(player->old_x) / 2 - 1];
3868 break;
3869 case 2: // front-mounted
3870 this_player->sidekick[LEFT_SIDEKICK].x = this_player->x;
3871 this_player->sidekick[LEFT_SIDEKICK].y = MAX(10, this_player->y - 20);
3872 break;
3873 case 4: // orbitting
3874 this_player->sidekick[LEFT_SIDEKICK].x = this_player->x + roundf(sinf(optionSatelliteRotate) * 20);
3875 this_player->sidekick[LEFT_SIDEKICK].y = this_player->y + roundf(cosf(optionSatelliteRotate) * 20);
3876 break;
3877 }
3878
3879 switch (this_player->sidekick[RIGHT_SIDEKICK].style)
3880 {
3881 case 4: // orbitting
3882 this_player->sidekick[RIGHT_SIDEKICK].x = this_player->x - roundf(sinf(optionSatelliteRotate) * 20);
3883 this_player->sidekick[RIGHT_SIDEKICK].y = this_player->y - roundf(cosf(optionSatelliteRotate) * 20);
3884 break;
3885 case 1: // trailing
3886 case 3:
3887 this_player->sidekick[RIGHT_SIDEKICK].x = this_player->old_x[0];
3888 this_player->sidekick[RIGHT_SIDEKICK].y = this_player->old_y[0];
3889 break;
3890 case 2: // front-mounted
3891 if (!optionAttachmentLinked)
3892 {
3893 this_player->sidekick[RIGHT_SIDEKICK].y += optionAttachmentMove / 2;
3894 if (optionAttachmentMove >= -2)
3895 {
3896 if (optionAttachmentReturn)
3897 temp = 2;
3898 else
3899 temp = 0;
3900
3901 if (this_player->sidekick[RIGHT_SIDEKICK].y > (this_player->y - 20) + 5)
3902 {
3903 temp = 2;
3904 optionAttachmentMove -= 1 + optionAttachmentReturn;
3905 }
3906 else if (this_player->sidekick[RIGHT_SIDEKICK].y > (this_player->y - 20) - 0)
3907 {
3908 temp = 3;
3909 if (optionAttachmentMove > 0)
3910 optionAttachmentMove--;
3911 else
3912 optionAttachmentMove++;
3913 }
3914 else if (this_player->sidekick[RIGHT_SIDEKICK].y > (this_player->y - 20) - 5)
3915 {
3916 temp = 2;
3917 optionAttachmentMove++;
3918 }
3919 else if (optionAttachmentMove < 2 + optionAttachmentReturn * 4)
3920 {
3921 optionAttachmentMove += 1 + optionAttachmentReturn;
3922 }
3923
3924 if (optionAttachmentReturn)
3925 temp = temp * 2;
3926 if (abs(this_player->sidekick[RIGHT_SIDEKICK].x - this_player->x) < temp)
3927 temp = 1;
3928
3929 if (this_player->sidekick[RIGHT_SIDEKICK].x > this_player->x)
3930 this_player->sidekick[RIGHT_SIDEKICK].x -= temp;
3931 else if (this_player->sidekick[RIGHT_SIDEKICK].x < this_player->x)
3932 this_player->sidekick[RIGHT_SIDEKICK].x += temp;
3933
3934 if (abs(this_player->sidekick[RIGHT_SIDEKICK].y - (this_player->y - 20)) + abs(this_player->sidekick[RIGHT_SIDEKICK].x - this_player->x) < 8)
3935 {
3936 optionAttachmentLinked = true;
3937 soundQueue[2] = S_CLINK;
3938 }
3939
3940 if (button[3-1])
3941 optionAttachmentReturn = true;
3942 }
3943 else // sidekick needs to catch up to player
3944 {
3945 optionAttachmentMove += 1 + optionAttachmentReturn;
3946 JE_setupExplosion(this_player->sidekick[RIGHT_SIDEKICK].x + 1, this_player->sidekick[RIGHT_SIDEKICK].y + 10, 0, 0, false, false);
3947 }
3948 }
3949 else
3950 {
3951 this_player->sidekick[RIGHT_SIDEKICK].x = this_player->x;
3952 this_player->sidekick[RIGHT_SIDEKICK].y = this_player->y - 20;
3953 if (button[3-1])
3954 {
3955 optionAttachmentLinked = false;
3956 optionAttachmentReturn = false;
3957 optionAttachmentMove = -20;
3958 soundQueue[3] = S_WEAPON_26;
3959 }
3960 }
3961
3962 if (this_player->sidekick[RIGHT_SIDEKICK].y < 10)
3963 this_player->sidekick[RIGHT_SIDEKICK].y = 10;
3964 break;
3965 }
3966
3967 if (playerNum_ == 2 || !twoPlayerMode) // if player has sidekicks
3968 {
3969 for (uint i = 0; i < COUNTOF(player->items.sidekick); ++i)
3970 {
3971 uint shot_i = (i == 0) ? SHOT_LEFT_SIDEKICK : SHOT_RIGHT_SIDEKICK;
3972
3973 JE_OptionType *this_option = &options[this_player->items.sidekick[i]];
3974
3975 // fire/refill sidekick
3976 if (this_option->wport > 0)
3977 {
3978 if (shotRepeat[shot_i] > 0)
3979 {
3980 --shotRepeat[shot_i];
3981 }
3982 else
3983 {
3984 const int ammo_max = this_player->sidekick[i].ammo_max;
3985
3986 if (ammo_max > 0) // sidekick has limited ammo
3987 {
3988 if (this_player->sidekick[i].ammo_refill_ticks > 0)
3989 {
3990 --this_player->sidekick[i].ammo_refill_ticks;
3991 }
3992 else // refill one ammo
3993 {
3994 this_player->sidekick[i].ammo_refill_ticks = this_player->sidekick[i].ammo_refill_ticks_max;
3995
3996 if (this_player->sidekick[i].ammo < ammo_max)
3997 ++this_player->sidekick[i].ammo;
3998
3999 // draw sidekick refill ammo gauge
4000 const int y = hud_sidekick_y[twoPlayerMode ? 1 : 0][i] + 13;
4001 draw_segmented_gauge(VGAScreenSeg, 284, y, 112, 2, 2, MAX(1, ammo_max / 10), this_player->sidekick[i].ammo);
4002 }
4003
4004 if (button[1 + i] && this_player->sidekick[i].ammo > 0)
4005 {
4006 b = player_shot_create(this_option->wport, shot_i, this_player->sidekick[i].x, this_player->sidekick[i].y, *mouseX_, *mouseY_, this_option->wpnum + this_player->sidekick[i].charge, playerNum_);
4007
4008 --this_player->sidekick[i].ammo;
4009 if (this_player->sidekick[i].charge > 0)
4010 {
4011 shotMultiPos[shot_i] = 0;
4012 this_player->sidekick[i].charge = 0;
4013 }
4014 this_player->sidekick[i].charge_ticks = 20;
4015 this_player->sidekick[i].animation_enabled = true;
4016
4017 // draw sidekick discharge ammo gauge
4018 const int y = hud_sidekick_y[twoPlayerMode ? 1 : 0][i] + 13;
4019 fill_rectangle_xy(VGAScreenSeg, 284, y, 312, y + 2, 0);
4020 draw_segmented_gauge(VGAScreenSeg, 284, y, 112, 2, 2, MAX(1, ammo_max / 10), this_player->sidekick[i].ammo);
4021 }
4022 }
4023 else // has infinite ammo
4024 {
4025 if (button[0] || button[1 + i])
4026 {
4027 b = player_shot_create(this_option->wport, shot_i, this_player->sidekick[i].x, this_player->sidekick[i].y, *mouseX_, *mouseY_, this_option->wpnum + this_player->sidekick[i].charge, playerNum_);
4028
4029 if (this_player->sidekick[i].charge > 0)
4030 {
4031 shotMultiPos[shot_i] = 0;
4032 this_player->sidekick[i].charge = 0;
4033 }
4034 this_player->sidekick[i].charge_ticks = 20;
4035 this_player->sidekick[i].animation_enabled = true;
4036 }
4037 }
4038 }
4039 }
4040 }
4041 } // end of if player has sidekicks
4042 } // !endLevel
4043 } // this_player->is_alive
4044 } // moveOK
4045
4046 // draw sidekicks
4047 if ((playerNum_ == 2 || !twoPlayerMode) && !endLevel)
4048 {
4049 for (uint i = 0; i < COUNTOF(this_player->sidekick); ++i)
4050 {
4051 JE_OptionType *this_option = &options[this_player->items.sidekick[i]];
4052
4053 if (this_option->option > 0)
4054 {
4055 if (this_player->sidekick[i].animation_enabled)
4056 {
4057 if (++this_player->sidekick[i].animation_frame >= this_option->ani)
4058 {
4059 this_player->sidekick[i].animation_frame = 0;
4060 this_player->sidekick[i].animation_enabled = (this_option->option == 1);
4061 }
4062 }
4063
4064 const int x = this_player->sidekick[i].x,
4065 y = this_player->sidekick[i].y;
4066 const uint sprite = this_option->gr[this_player->sidekick[i].animation_frame] + this_player->sidekick[i].charge;
4067
4068 if (this_player->sidekick[i].style == 1 || this_player->sidekick[i].style == 2)
4069 blit_sprite2x2(VGAScreen, x - 6, y, eShapes[5], sprite);
4070 else
4071 blit_sprite2(VGAScreen, x, y, shapes9, sprite);
4072 }
4073
4074 if (--this_player->sidekick[i].charge_ticks == 0)
4075 {
4076 if (this_player->sidekick[i].charge < this_option->pwr)
4077 ++this_player->sidekick[i].charge;
4078 this_player->sidekick[i].charge_ticks = 20;
4079 }
4080 }
4081 }
4082 }
4083
JE_mainGamePlayerFunctions(void)4084 void JE_mainGamePlayerFunctions( void )
4085 {
4086 /*PLAYER MOVEMENT/MOUSE ROUTINES*/
4087
4088 if (endLevel && levelEnd > 0)
4089 {
4090 levelEnd--;
4091 levelEndWarp++;
4092 }
4093
4094 /*Reset Street-Fighter commands*/
4095 memset(SFExecuted, 0, sizeof(SFExecuted));
4096
4097 portConfigChange = false;
4098
4099 if (twoPlayerMode)
4100 {
4101 JE_playerMovement(&player[0],
4102 !galagaMode ? inputDevice[0] : 0, 1, shipGr, shipGrPtr,
4103 &mouseX, &mouseY);
4104 JE_playerMovement(&player[1],
4105 !galagaMode ? inputDevice[1] : 0, 2, shipGr2, shipGr2ptr,
4106 &mouseXB, &mouseYB);
4107 }
4108 else
4109 {
4110 JE_playerMovement(&player[0],
4111 0, 1, shipGr, shipGrPtr,
4112 &mouseX, &mouseY);
4113 }
4114
4115 /* == Parallax Map Scrolling == */
4116 if (twoPlayerMode)
4117 {
4118 tempX = (player[0].x + player[1].x) / 2;
4119 } else {
4120 tempX = player[0].x;
4121 }
4122
4123 tempW = floorf((260.0f - (tempX - 36.0f)) / (260.0f - 36.0f) * (24.0f * 3.0f) - 1.0f);
4124 mapX3Ofs = tempW;
4125 mapX3Pos = mapX3Ofs % 24;
4126 mapX3bpPos = 1 - (mapX3Ofs / 24);
4127
4128 mapX2Ofs = (tempW * 2) / 3;
4129 mapX2Pos = mapX2Ofs % 24;
4130 mapX2bpPos = 1 - (mapX2Ofs / 24);
4131
4132 oldMapXOfs = mapXOfs;
4133 mapXOfs = mapX2Ofs / 2;
4134 mapXPos = mapXOfs % 24;
4135 mapXbpPos = 1 - (mapXOfs / 24);
4136
4137 if (background3x1)
4138 {
4139 mapX3Ofs = mapXOfs;
4140 mapX3Pos = mapXPos;
4141 mapX3bpPos = mapXbpPos - 1;
4142 }
4143 }
4144
JE_getName(JE_byte pnum)4145 const char *JE_getName( JE_byte pnum )
4146 {
4147 if (pnum == thisPlayerNum && network_player_name[0] != '\0')
4148 return network_player_name;
4149 else if (network_opponent_name[0] != '\0')
4150 return network_opponent_name;
4151
4152 return miscText[47 + pnum];
4153 }
4154
JE_playerCollide(Player * this_player,JE_byte playerNum_)4155 void JE_playerCollide( Player *this_player, JE_byte playerNum_ )
4156 {
4157 char tempStr[256];
4158
4159 for (int z = 0; z < 100; z++)
4160 {
4161 if (enemyAvail[z] != 1)
4162 {
4163 int enemy_screen_x = enemy[z].ex + enemy[z].mapoffset;
4164
4165 if (abs(this_player->x - enemy_screen_x) < 12 && abs(this_player->y - enemy[z].ey) < 14)
4166 { /*Collide*/
4167 int evalue = enemy[z].evalue;
4168 if (evalue > 29999)
4169 {
4170 if (evalue == 30000) // spawn dragonwing in galaga mode, otherwise just a purple ball
4171 {
4172 this_player->cash += 100;
4173
4174 if (!galagaMode)
4175 {
4176 handle_got_purple_ball(this_player);
4177 }
4178 else
4179 {
4180 // spawn the dragonwing?
4181 if (twoPlayerMode)
4182 this_player->cash += 2400;
4183 twoPlayerMode = true;
4184 twoPlayerLinked = true;
4185 player[1].items.weapon[REAR_WEAPON].power = 1;
4186 player[1].armor = 10;
4187 player[1].is_alive = true;
4188 }
4189 enemyAvail[z] = 1;
4190 soundQueue[7] = S_POWERUP;
4191 }
4192 else if (superArcadeMode != SA_NONE && evalue > 30000)
4193 {
4194 shotMultiPos[SHOT_FRONT] = 0;
4195 shotRepeat[SHOT_FRONT] = 10;
4196
4197 tempW = SAWeapon[superArcadeMode-1][evalue - 30000-1];
4198
4199 // if picked up already-owned weapon, power weapon up
4200 if (tempW == player[0].items.weapon[FRONT_WEAPON].id)
4201 {
4202 this_player->cash += 1000;
4203 power_up_weapon(this_player, FRONT_WEAPON);
4204 }
4205 // else weapon also gives purple ball
4206 else
4207 {
4208 handle_got_purple_ball(this_player);
4209 }
4210
4211 player[0].items.weapon[FRONT_WEAPON].id = tempW;
4212 this_player->cash += 200;
4213 soundQueue[7] = S_POWERUP;
4214 enemyAvail[z] = 1;
4215 }
4216 else if (evalue > 32100)
4217 {
4218 if (playerNum_ == 1)
4219 {
4220 this_player->cash += 250;
4221 player[0].items.special = evalue - 32100;
4222 shotMultiPos[SHOT_SPECIAL] = 0;
4223 shotRepeat[SHOT_SPECIAL] = 10;
4224 shotMultiPos[SHOT_SPECIAL2] = 0;
4225 shotRepeat[SHOT_SPECIAL2] = 0;
4226
4227 if (isNetworkGame)
4228 sprintf(tempStr, "%s %s %s", JE_getName(1), miscTextB[4-1], special[evalue - 32100].name);
4229 else if (twoPlayerMode)
4230 sprintf(tempStr, "%s %s", miscText[43-1], special[evalue - 32100].name);
4231 else
4232 sprintf(tempStr, "%s %s", miscText[64-1], special[evalue - 32100].name);
4233 JE_drawTextWindow(tempStr);
4234 soundQueue[7] = S_POWERUP;
4235 enemyAvail[z] = 1;
4236 }
4237 }
4238 else if (evalue > 32000)
4239 {
4240 if (playerNum_ == 2)
4241 {
4242 enemyAvail[z] = 1;
4243 if (isNetworkGame)
4244 sprintf(tempStr, "%s %s %s", JE_getName(2), miscTextB[4-1], options[evalue - 32000].name);
4245 else
4246 sprintf(tempStr, "%s %s", miscText[44-1], options[evalue - 32000].name);
4247 JE_drawTextWindow(tempStr);
4248
4249 // if picked up a different sidekick than player already has, then reset sidekicks to least powerful, else power them up
4250 if (evalue - 32000u != player[1].items.sidekick_series)
4251 {
4252 player[1].items.sidekick_series = evalue - 32000;
4253 player[1].items.sidekick_level = 101;
4254 }
4255 else if (player[1].items.sidekick_level < 103)
4256 {
4257 ++player[1].items.sidekick_level;
4258 }
4259
4260 uint temp = player[1].items.sidekick_level - 100 - 1;
4261 for (uint i = 0; i < COUNTOF(player[1].items.sidekick); ++i)
4262 player[1].items.sidekick[i] = optionSelect[player[1].items.sidekick_series][temp][i];
4263
4264
4265 shotMultiPos[SHOT_LEFT_SIDEKICK] = 0;
4266 shotMultiPos[SHOT_RIGHT_SIDEKICK] = 0;
4267 JE_drawOptions();
4268 soundQueue[7] = S_POWERUP;
4269 }
4270 else if (onePlayerAction)
4271 {
4272 enemyAvail[z] = 1;
4273 sprintf(tempStr, "%s %s", miscText[64-1], options[evalue - 32000].name);
4274 JE_drawTextWindow(tempStr);
4275
4276 for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i)
4277 player[0].items.sidekick[i] = evalue - 32000;
4278 shotMultiPos[SHOT_LEFT_SIDEKICK] = 0;
4279 shotMultiPos[SHOT_RIGHT_SIDEKICK] = 0;
4280
4281 JE_drawOptions();
4282 soundQueue[7] = S_POWERUP;
4283 }
4284 if (enemyAvail[z] == 1)
4285 this_player->cash += 250;
4286 }
4287 else if (evalue > 31000)
4288 {
4289 this_player->cash += 250;
4290 if (playerNum_ == 2)
4291 {
4292 if (isNetworkGame)
4293 sprintf(tempStr, "%s %s %s", JE_getName(2), miscTextB[4-1], weaponPort[evalue - 31000].name);
4294 else
4295 sprintf(tempStr, "%s %s", miscText[44-1], weaponPort[evalue - 31000].name);
4296 JE_drawTextWindow(tempStr);
4297 player[1].items.weapon[REAR_WEAPON].id = evalue - 31000;
4298 shotMultiPos[SHOT_REAR] = 0;
4299 enemyAvail[z] = 1;
4300 soundQueue[7] = S_POWERUP;
4301 }
4302 else if (onePlayerAction)
4303 {
4304 sprintf(tempStr, "%s %s", miscText[64-1], weaponPort[evalue - 31000].name);
4305 JE_drawTextWindow(tempStr);
4306 player[0].items.weapon[REAR_WEAPON].id = evalue - 31000;
4307 shotMultiPos[SHOT_REAR] = 0;
4308 enemyAvail[z] = 1;
4309 soundQueue[7] = S_POWERUP;
4310
4311 if (player[0].items.weapon[REAR_WEAPON].power == 0) // does this ever happen?
4312 player[0].items.weapon[REAR_WEAPON].power = 1;
4313 }
4314 }
4315 else if (evalue > 30000)
4316 {
4317 if (playerNum_ == 1 && twoPlayerMode)
4318 {
4319 if (isNetworkGame)
4320 sprintf(tempStr, "%s %s %s", JE_getName(1), miscTextB[4-1], weaponPort[evalue - 30000].name);
4321 else
4322 sprintf(tempStr, "%s %s", miscText[43-1], weaponPort[evalue - 30000].name);
4323 JE_drawTextWindow(tempStr);
4324 player[0].items.weapon[FRONT_WEAPON].id = evalue - 30000;
4325 shotMultiPos[SHOT_FRONT] = 0;
4326 enemyAvail[z] = 1;
4327 soundQueue[7] = S_POWERUP;
4328 }
4329 else if (onePlayerAction)
4330 {
4331 sprintf(tempStr, "%s %s", miscText[64-1], weaponPort[evalue - 30000].name);
4332 JE_drawTextWindow(tempStr);
4333 player[0].items.weapon[FRONT_WEAPON].id = evalue - 30000;
4334 shotMultiPos[SHOT_FRONT] = 0;
4335 enemyAvail[z] = 1;
4336 soundQueue[7] = S_POWERUP;
4337 }
4338
4339 if (enemyAvail[z] == 1)
4340 {
4341 player[0].items.special = specialArcadeWeapon[evalue - 30000-1];
4342 if (player[0].items.special > 0)
4343 {
4344 shotMultiPos[SHOT_SPECIAL] = 0;
4345 shotRepeat[SHOT_SPECIAL] = 0;
4346 shotMultiPos[SHOT_SPECIAL2] = 0;
4347 shotRepeat[SHOT_SPECIAL2] = 0;
4348 }
4349 this_player->cash += 250;
4350 }
4351
4352 }
4353 }
4354 else if (evalue > 20000)
4355 {
4356 if (twoPlayerLinked)
4357 {
4358 // share the armor evenly between linked players
4359 for (uint i = 0; i < COUNTOF(player); ++i)
4360 {
4361 player[i].armor += (evalue - 20000) / COUNTOF(player);
4362 if (player[i].armor > 28)
4363 player[i].armor = 28;
4364 }
4365 }
4366 else
4367 {
4368 this_player->armor += evalue - 20000;
4369 if (this_player->armor > 28)
4370 this_player->armor = 28;
4371 }
4372 enemyAvail[z] = 1;
4373 VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
4374 JE_drawArmor();
4375 VGAScreen = game_screen; /* side-effect of game_screen */
4376 soundQueue[7] = S_POWERUP;
4377 }
4378 else if (evalue > 10000 && enemyAvail[z] == 2)
4379 {
4380 if (!bonusLevel)
4381 {
4382 play_song(30); /*Zanac*/
4383 bonusLevel = true;
4384 nextLevel = evalue - 10000;
4385 enemyAvail[z] = 1;
4386 displayTime = 150;
4387 }
4388 }
4389 else if (enemy[z].scoreitem)
4390 {
4391 enemyAvail[z] = 1;
4392 soundQueue[7] = S_ITEM;
4393 if (evalue == 1)
4394 {
4395 cubeMax++;
4396 soundQueue[3] = V_DATA_CUBE;
4397 }
4398 else if (evalue == -1) // got front weapon powerup
4399 {
4400 if (isNetworkGame)
4401 sprintf(tempStr, "%s %s %s", JE_getName(1), miscTextB[4-1], miscText[45-1]);
4402 else if (twoPlayerMode)
4403 sprintf(tempStr, "%s %s", miscText[43-1], miscText[45-1]);
4404 else
4405 strcpy(tempStr, miscText[45-1]);
4406 JE_drawTextWindow(tempStr);
4407
4408 power_up_weapon(&player[0], FRONT_WEAPON);
4409 soundQueue[7] = S_POWERUP;
4410 }
4411 else if (evalue == -2) // got rear weapon powerup
4412 {
4413 if (isNetworkGame)
4414 sprintf(tempStr, "%s %s %s", JE_getName(2), miscTextB[4-1], miscText[46-1]);
4415 else if (twoPlayerMode)
4416 sprintf(tempStr, "%s %s", miscText[44-1], miscText[46-1]);
4417 else
4418 strcpy(tempStr, miscText[46-1]);
4419 JE_drawTextWindow(tempStr);
4420
4421 power_up_weapon(twoPlayerMode ? &player[1] : &player[0], REAR_WEAPON);
4422 soundQueue[7] = S_POWERUP;
4423 }
4424 else if (evalue == -3)
4425 {
4426 // picked up orbiting asteroid killer
4427 shotMultiPos[SHOT_MISC] = 0;
4428 b = player_shot_create(0, SHOT_MISC, this_player->x, this_player->y, mouseX, mouseY, 104, playerNum_);
4429 shotAvail[z] = 0;
4430 }
4431 else if (evalue == -4)
4432 {
4433 if (player[playerNum_-1].superbombs < 10)
4434 ++player[playerNum_-1].superbombs;
4435 }
4436 else if (evalue == -5)
4437 {
4438 player[0].items.weapon[FRONT_WEAPON].id = 25; // HOT DOG!
4439 player[0].items.weapon[REAR_WEAPON].id = 26;
4440 player[1].items.weapon[REAR_WEAPON].id = 26;
4441
4442 player[0].last_items = player[0].items;
4443
4444 for (uint i = 0; i < COUNTOF(player); ++i)
4445 player[i].weapon_mode = 1;
4446
4447 memset(shotMultiPos, 0, sizeof(shotMultiPos));
4448 }
4449 else if (twoPlayerLinked)
4450 {
4451 // players get equal share of pick-up cash when linked
4452 for (uint i = 0; i < COUNTOF(player); ++i)
4453 player[i].cash += evalue / COUNTOF(player);
4454 }
4455 else
4456 {
4457 this_player->cash += evalue;
4458 }
4459 JE_setupExplosion(enemy_screen_x, enemy[z].ey, 0, enemyDat[enemy[z].enemytype].explosiontype, true, false);
4460 }
4461 else if (this_player->invulnerable_ticks == 0 && enemyAvail[z] == 0 &&
4462 (enemyDat[enemy[z].enemytype].explosiontype & 1) == 0) // explosiontype & 1 == 0: not ground enemy
4463 {
4464 int armorleft = enemy[z].armorleft;
4465 if (armorleft > damageRate)
4466 armorleft = damageRate;
4467
4468 JE_playerDamage(armorleft, this_player);
4469
4470 // player ship gets push-back from collision
4471 if (enemy[z].armorleft > 0)
4472 {
4473 this_player->x_velocity += (enemy[z].exc * enemy[z].armorleft) / 2;
4474 this_player->y_velocity += (enemy[z].eyc * enemy[z].armorleft) / 2;
4475 }
4476
4477 int armorleft2 = enemy[z].armorleft;
4478 if (armorleft2 == 255)
4479 armorleft2 = 30000;
4480
4481 temp = enemy[z].linknum;
4482 if (temp == 0)
4483 temp = 255;
4484
4485 b = z;
4486
4487 if (armorleft2 > armorleft)
4488 {
4489 // damage enemy
4490 if (enemy[z].armorleft != 255)
4491 enemy[z].armorleft -= armorleft;
4492 soundQueue[5] = S_ENEMY_HIT;
4493 }
4494 else
4495 {
4496 // kill enemy
4497 for (temp2 = 0; temp2 < 100; temp2++)
4498 {
4499 if (enemyAvail[temp2] != 1)
4500 {
4501 temp3 = enemy[temp2].linknum;
4502 if (temp2 == b ||
4503 (temp != 255 &&
4504 (temp == temp3 || temp - 100 == temp3
4505 || (temp3 > 40 && temp3 / 20 == temp / 20 && temp3 <= temp))))
4506 {
4507 int enemy_screen_x = enemy[temp2].ex + enemy[temp2].mapoffset;
4508
4509 enemy[temp2].linknum = 0;
4510
4511 enemyAvail[temp2] = 1;
4512
4513 if (enemyDat[enemy[temp2].enemytype].esize == 1)
4514 {
4515 JE_setupExplosionLarge(enemy[temp2].enemyground, enemy[temp2].explonum, enemy_screen_x, enemy[temp2].ey);
4516 soundQueue[6] = S_EXPLOSION_9;
4517 }
4518 else
4519 {
4520 JE_setupExplosion(enemy_screen_x, enemy[temp2].ey, 0, 1, false, false);
4521 soundQueue[5] = S_EXPLOSION_4;
4522 }
4523 }
4524 }
4525 }
4526 enemyAvail[z] = 1;
4527 }
4528 }
4529 }
4530
4531 }
4532 }
4533 }
4534
4535