Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
9169 turbocat 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 "varz.h"
20
 
21
#include "config.h"
22
#include "editship.h"
23
#include "episodes.h"
24
#include "joystick.h"
25
#include "lds_play.h"
26
#include "loudness.h"
27
#include "mainint.h"
28
#include "mouse.h"
29
#include "mtrand.h"
30
#include "network.h"
31
#include "nortsong.h"
32
#include "nortvars.h"
33
#include "opentyr.h"
34
#include "shots.h"
35
#include "sprite.h"
36
#include "vga256d.h"
37
#include "video.h"
38
 
39
JE_integer tempDat, tempDat2, tempDat3;
40
 
41
const JE_byte SANextShip[SA + 2] /* [0..SA + 1] */ = { 3, 9, 6, 2, 5, 1, 4, 3, 7 }; // 0 -> 3 -> 2 -> 6 -> 4 -> 5 -> 1 -> 9 -> 7
42
const JE_word SASpecialWeapon[SA] /* [1..SA] */  = { 7, 8, 9, 10, 11, 12, 13 };
43
const JE_word SASpecialWeaponB[SA] /* [1..SA] */ = {37, 6, 15, 40, 16, 14, 41 };
44
const JE_byte SAShip[SA] /* [1..SA] */ = { 3, 1, 5, 10, 2, 11, 12 };
45
const JE_word SAWeapon[SA][5] /* [1..SA, 1..5] */ =
46
{  /*  R  Bl  Bk  G   P */
47
	{  9, 31, 32, 33, 34 },  /* Stealth Ship */
48
	{ 19,  8, 22, 41, 34 },  /* StormWind    */
49
	{ 27,  5, 20, 42, 31 },  /* Techno       */
50
	{ 15,  3, 28, 22, 12 },  /* Enemy        */
51
	{ 23, 35, 25, 14,  6 },  /* Weird        */
52
	{  2,  5, 21,  4,  7 },  /* Unknown      */
53
	{ 40, 38, 37, 41, 36 }   /* NortShip Z   */
54
};
55
 
56
const JE_byte specialArcadeWeapon[PORT_NUM] /* [1..Portnum] */ =
57
{
58
	17,17,18,0,0,0,10,0,0,0,0,0,44,0,10,0,19,0,0,-0,0,0,0,0,0,0,
59
	-0,0,0,0,45,0,0,0,0,0,0,0,0,0,0,0
60
};
61
 
62
const JE_byte optionSelect[16][3][2] /* [0..15, 1..3, 1..2] */ =
63
{	/*  MAIN    OPT    FRONT */
64
	{ { 0, 0},{ 0, 0},{ 0, 0} },  /**/
65
	{ { 1, 1},{16,16},{30,30} },  /*Single Shot*/
66
	{ { 2, 2},{29,29},{29,20} },  /*Dual Shot*/
67
	{ { 3, 3},{21,21},{12, 0} },  /*Charge Cannon*/
68
	{ { 4, 4},{18,18},{16,23} },  /*Vulcan*/
69
	{ { 0, 0},{ 0, 0},{ 0, 0} },  /**/
70
	{ { 6, 6},{29,16},{ 0,22} },  /*Super Missile*/
71
	{ { 7, 7},{19,19},{19,28} },  /*Atom Bomb*/
72
	{ { 0, 0},{ 0, 0},{ 0, 0} },  /**/
73
	{ { 0, 0},{ 0, 0},{ 0, 0} },  /**/
74
	{ {10,10},{21,21},{21,27} },  /*Mini Missile*/
75
	{ { 0, 0},{ 0, 0},{ 0, 0} },  /**/
76
	{ { 0, 0},{ 0, 0},{ 0, 0} },  /**/
77
	{ {13,13},{17,17},{13,26} },  /*MicroBomb*/
78
	{ { 0, 0},{ 0, 0},{ 0, 0} },  /**/
79
	{ {15,15},{15,16},{15,16} }   /*Post-It*/
80
};
81
 
82
const JE_word PGR[21] /* [1..21] */ =
83
{
84
	4,
85
	1,2,3,
86
	41-21,57-21,73-21,89-21,105-21,
87
	121-21,137-21,153-21,
88
	151,151,151,151,73-21,73-21,1,2,4
89
	/*151,151,151*/
90
};
91
const JE_byte PAni[21] /* [1..21] */ = {1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1};
92
 
93
const JE_word linkGunWeapons[38] /* [1..38] */ =
94
{
95
	0,0,0,0,0,0,0,0,444,445,446,447,0,448,449,0,0,0,0,0,450,451,0,506,0,564,
96
	  445,446,447,448,449,445,446,447,448,449,450,451
97
};
98
const JE_word chargeGunWeapons[38] /* [1..38] */ =
99
{
100
	0,0,0,0,0,0,0,0,476,458,464,482,0,488,470,0,0,0,0,0,494,500,0,528,0,558,
101
	  458,458,458,458,458,458,458,458,458,458,458,458
102
};
103
const JE_byte randomEnemyLaunchSounds[3] /* [1..3] */ = {13,6,26};
104
 
105
/* YKS: Twiddle cheat sheet:
106
 * 1: UP
107
 * 2: DOWN
108
 * 3: LEFT
109
 * 4: RIGHT
110
 * 5: UP+FIRE
111
 * 6: DOWN+FIRE
112
 * 7: LEFT+FIRE
113
 * 8: RIGHT+FIRE
114
 * 9: Release all keys (directions and fire)
115
 */
116
const JE_byte keyboardCombos[26][8] /* [1..26, 1..8] */ =
117
{
118
	{ 2, 1,   2,   5, 137,           0, 0, 0}, /*Invulnerability*/
119
	{ 4, 3,   2,   5, 138,           0, 0, 0}, /*Atom Bomb*/
120
	{ 3, 4,   6, 139,             0, 0, 0, 0}, /*Seeker Bombs*/
121
	{ 2, 5, 142,               0, 0, 0, 0, 0}, /*Ice Blast*/
122
	{ 6, 2,   6, 143,             0, 0, 0, 0}, /*Auto Repair*/
123
	{ 6, 7,   5,   8,   6,   7,  5, 112     }, /*Spin Wave*/
124
	{ 7, 8, 101,               0, 0, 0, 0, 0}, /*Repulsor*/
125
	{ 1, 7,   6, 146,             0, 0, 0, 0}, /*Protron Field*/
126
	{ 8, 6,   7,   1, 120,           0, 0, 0}, /*Minefield*/
127
	{ 3, 6,   8,   5, 121,           0, 0, 0}, /*Post-It Blast*/
128
	{ 1, 2,   7,   8, 119,           0, 0, 0}, /*Drone Ship - TBC*/
129
	{ 3, 4,   3,   6, 123,           0, 0, 0}, /*Repair Player 2*/
130
	{ 6, 7,   5,   8, 124,           0, 0, 0}, /*Super Bomb - TBC*/
131
	{ 1, 6, 125,               0, 0, 0, 0, 0}, /*Hot Dog*/
132
	{ 9, 5, 126,               0, 0, 0, 0, 0}, /*Lightning UP      */
133
	{ 1, 7, 127,               0, 0, 0, 0, 0}, /*Lightning UP+LEFT */
134
	{ 1, 8, 128,               0, 0, 0, 0, 0}, /*Lightning UP+RIGHT*/
135
	{ 9, 7, 129,               0, 0, 0, 0, 0}, /*Lightning    LEFT */
136
	{ 9, 8, 130,               0, 0, 0, 0, 0}, /*Lightning    RIGHT*/
137
	{ 4, 2,   3,   5, 131,           0, 0, 0}, /*Warfly            */
138
	{ 3, 1,   2,   8, 132,           0, 0, 0}, /*FrontBlaster      */
139
	{ 2, 4,   5, 133,             0, 0, 0, 0}, /*Gerund            */
140
	{ 3, 4,   2,   8, 134,           0, 0, 0}, /*FireBomb          */
141
	{ 1, 4,   6, 135,             0, 0, 0, 0}, /*Indigo            */
142
	{ 1, 3,   6, 137,             0, 0, 0, 0}, /*Invulnerability [easier] */
143
	{ 1, 4,   3,   4,   7, 136,         0, 0}  /*D-Media Protron Drone    */
144
};
145
 
146
const JE_byte shipCombosB[21] /* [1..21] */ =
147
	{15,16,17,18,19,20,21,22,23,24, 7, 8, 5,25,14, 4, 6, 3, 9, 2,26};
148
  /*!! SUPER Tyrian !!*/
149
const JE_byte superTyrianSpecials[4] /* [1..4] */ = {1,2,4,5};
150
 
151
const JE_byte shipCombos[14][3] /* [0..12, 1..3] */ =
152
{
153
	{ 5, 4, 7},  /*2nd Player ship*/
154
	{ 1, 2, 0},  /*USP Talon*/
155
	{14, 4, 0},  /*Super Carrot*/
156
	{ 4, 5, 0},  /*Gencore Phoenix*/
157
	{ 6, 5, 0},  /*Gencore Maelstrom*/
158
	{ 7, 8, 0},  /*MicroCorp Stalker*/
159
	{ 7, 9, 0},  /*MicroCorp Stalker-B*/
160
	{10, 3, 5},  /*Prototype Stalker-C*/
161
	{ 5, 8, 9},  /*Stalker*/
162
	{ 1, 3, 0},  /*USP Fang*/
163
	{ 7,16,17},  /*U-Ship*/
164
	{ 2,11,12},  /*1st Player ship*/
165
	{ 3, 8,10},  /*Nort ship*/
166
	{ 0, 0, 0}   // Dummy entry added for Stalker 21.126
167
};
168
 
169
/*Street-Fighter Commands*/
170
JE_byte SFCurrentCode[2][21]; /* [1..2, 1..21] */
171
JE_byte SFExecuted[2]; /* [1..2] */
172
 
173
/*Special General Data*/
174
JE_byte lvlFileNum;
175
JE_word maxEvent, eventLoc;
176
/*JE_word maxenemies;*/
177
JE_word tempBackMove, explodeMove; /*Speed of background movement*/
178
JE_byte levelEnd;
179
JE_word levelEndFxWait;
180
JE_shortint levelEndWarp;
181
JE_boolean endLevel, reallyEndLevel, waitToEndLevel, playerEndLevel,
182
           normalBonusLevelCurrent, bonusLevelCurrent,
183
           smallEnemyAdjust, readyToEndLevel, quitRequested;
184
 
185
JE_byte newPL[10]; /* [0..9] */ /*Eventsys event 75 parameter*/
186
JE_word returnLoc;
187
JE_boolean returnActive;
188
JE_word galagaShotFreq;
189
JE_longint galagaLife;
190
 
191
JE_boolean debug = false; /*Debug Mode*/
192
Uint32 debugTime, lastDebugTime;
193
JE_longint debugHistCount;
194
JE_real debugHist;
195
JE_word curLoc; /*Current Pixel location of background 1*/
196
 
197
JE_boolean firstGameOver, gameLoaded, enemyStillExploding;
198
 
199
 
200
/* Destruction Ratio */
201
JE_word totalEnemy;
202
JE_word enemyKilled;
203
 
204
/* Shape/Map Data - All in one Segment! */
205
struct JE_MegaDataType1 megaData1;
206
struct JE_MegaDataType2 megaData2;
207
struct JE_MegaDataType3 megaData3;
208
 
209
/* Secret Level Display */
210
JE_byte flash;
211
JE_shortint flashChange;
212
JE_byte displayTime;
213
 
214
/* Demo Stuff */
215
bool play_demo = false, record_demo = false, stopped_demo = false;
216
Uint8 demo_num = 0;
217
FILE *demo_file = NULL;
218
 
219
Uint8 demo_keys, next_demo_keys;
220
Uint16 demo_keys_wait;
221
 
222
/* Sound Effects Queue */
223
JE_byte soundQueue[8]; /* [0..7] */
224
 
225
/*Level Event Data*/
226
JE_boolean enemyContinualDamage;
227
JE_boolean enemiesActive;
228
JE_boolean forceEvents;
229
JE_boolean stopBackgrounds;
230
JE_byte stopBackgroundNum;
231
JE_byte damageRate;  /*Rate at which a player takes damage*/
232
JE_boolean background3x1;  /*Background 3 enemies use Background 1 X offset*/
233
JE_boolean background3x1b; /*Background 3 enemies moved 8 pixels left*/
234
 
235
JE_boolean levelTimer;
236
JE_word    levelTimerCountdown;
237
JE_word    levelTimerJumpTo;
238
JE_boolean randomExplosions;
239
 
240
JE_boolean editShip1, editShip2;
241
 
242
JE_boolean globalFlags[10]; /* [1..10] */
243
JE_byte levelSong;
244
 
245
/* DESTRUCT game */
246
JE_boolean loadDestruct;
247
 
248
/* MapView Data */
249
JE_word mapOrigin, mapPNum;
250
JE_byte mapPlanet[5], mapSection[5]; /* [1..5] */
251
 
252
/* Interface Constants */
253
JE_boolean moveTyrianLogoUp;
254
JE_boolean skipStarShowVGA;
255
 
256
/*EnemyData*/
257
JE_MultiEnemyType enemy;
258
JE_EnemyAvailType enemyAvail;  /* values: 0: used, 1: free, 2: secret pick-up */
259
JE_word enemyOffset;
260
JE_word enemyOnScreen;
261
JE_byte enemyShapeTables[6]; /* [1..6] */
262
JE_word superEnemy254Jump;
263
 
264
/*EnemyShotData*/
265
JE_boolean fireButtonHeld;
266
JE_boolean enemyShotAvail[ENEMY_SHOT_MAX]; /* [1..Enemyshotmax] */
267
EnemyShotType enemyShot[ENEMY_SHOT_MAX]; /* [1..Enemyshotmax]  */
268
 
269
/* Player Shot Data */
270
JE_byte     zinglonDuration;
271
JE_byte     astralDuration;
272
JE_word     flareDuration;
273
JE_boolean  flareStart;
274
JE_shortint flareColChg;
275
JE_byte     specialWait;
276
JE_byte     nextSpecialWait;
277
JE_boolean  spraySpecial;
278
JE_byte     doIced;
279
JE_boolean  infiniteShot;
280
 
281
/*PlayerData*/
282
JE_boolean allPlayersGone; /*Both players dead and finished exploding*/
283
 
284
const uint shadowYDist = 10;
285
 
286
JE_real optionSatelliteRotate;
287
 
288
JE_integer optionAttachmentMove;
289
JE_boolean optionAttachmentLinked, optionAttachmentReturn;
290
 
291
 
292
JE_byte chargeWait, chargeLevel, chargeMax, chargeGr, chargeGrWait;
293
 
294
JE_word neat;
295
 
296
 
297
/*ExplosionData*/
298
explosion_type explosions[MAX_EXPLOSIONS]; /* [1..ExplosionMax] */
299
JE_integer explosionFollowAmountX, explosionFollowAmountY;
300
 
301
/*Repeating Explosions*/
302
rep_explosion_type rep_explosions[MAX_REPEATING_EXPLOSIONS]; /* [1..20] */
303
 
304
/*SuperPixels*/
305
superpixel_type superpixels[MAX_SUPERPIXELS]; /* [0..MaxSP] */
306
unsigned int last_superpixel;
307
 
308
/*Temporary Numbers*/
309
JE_byte temp, temp2, temp3;
310
JE_word tempX, tempY;
311
JE_word tempW;
312
 
313
JE_boolean doNotSaveBackup;
314
 
315
JE_word x, y;
316
JE_integer b;
317
 
318
JE_byte **BKwrap1to, **BKwrap2to, **BKwrap3to,
319
        **BKwrap1, **BKwrap2, **BKwrap3;
320
 
321
JE_shortint specialWeaponFilter, specialWeaponFreq;
322
JE_word     specialWeaponWpn;
323
JE_boolean  linkToPlayer;
324
 
325
JE_word shipGr, shipGr2;
326
Sprite2_array *shipGrPtr, *shipGr2ptr;
327
 
328
void JE_getShipInfo( void )
329
{
330
	JE_boolean extraShip, extraShip2;
331
 
332
	shipGrPtr = &shapes9;
333
	shipGr2ptr = &shapes9;
334
 
335
	powerAdd  = powerSys[player[0].items.generator].power;
336
 
337
	extraShip = player[0].items.ship > 90;
338
	if (extraShip)
339
	{
340
		JE_byte base = (player[0].items.ship - 91) * 15;
341
		shipGr = JE_SGr(player[0].items.ship - 90, &shipGrPtr);
342
		player[0].armor = extraShips[base + 7];
343
	}
344
	else
345
	{
346
		shipGr = ships[player[0].items.ship].shipgraphic;
347
		player[0].armor = ships[player[0].items.ship].dmg;
348
	}
349
 
350
	extraShip2 = player[1].items.ship > 90;
351
	if (extraShip2)
352
	{
353
		JE_byte base2 = (player[1].items.ship - 91) * 15;
354
		shipGr2 = JE_SGr(player[1].items.ship - 90, &shipGr2ptr);
355
		player[1].armor = extraShips[base2 + 7]; /* bug? */
356
	}
357
	else
358
	{
359
		shipGr2 = 0;
360
		player[1].armor = 10;
361
	}
362
 
363
	for (uint i = 0; i < COUNTOF(player); ++i)
364
	{
365
		player[i].initial_armor = player[i].armor;
366
 
367
 
368
		uint temp = ((i == 0 && extraShip) ||
369
		             (i == 1 && extraShip2)) ? 2 : ships[player[i].items.ship].ani;
370
 
371
		if (temp == 0)
372
		{
373
			player[i].shot_hit_area_x = 12;
374
			player[i].shot_hit_area_y = 10;
375
		}
376
		else
377
		{
378
			player[i].shot_hit_area_x = 11;
379
			player[i].shot_hit_area_y = 14;
380
		}
381
	}
382
}
383
 
384
JE_word JE_SGr( JE_word ship, Sprite2_array **ptr )
385
{
386
	const JE_word GR[15] /* [1..15] */ = {233, 157, 195, 271, 81, 0, 119, 5, 43, 81, 119, 157, 195, 233, 271};
387
 
388
	JE_word tempW = extraShips[(ship - 1) * 15];
389
	if (tempW > 7)
390
		*ptr = extraShapes;
391
 
392
	return GR[tempW-1];
393
}
394
 
395
void JE_drawOptions( void )
396
{
397
	SDL_Surface *temp_surface = VGAScreen;
398
	VGAScreen = VGAScreenSeg;
399
 
400
	Player *this_player = &player[twoPlayerMode ? 1 : 0];
401
 
402
	for (uint i = 0; i < COUNTOF(this_player->sidekick); ++i)
403
	{
404
		JE_OptionType *this_option = &options[this_player->items.sidekick[i]];
405
 
406
		this_player->sidekick[i].ammo =
407
		this_player->sidekick[i].ammo_max = this_option->ammo;
408
 
409
		this_player->sidekick[i].ammo_refill_ticks =
410
		this_player->sidekick[i].ammo_refill_ticks_max = (105 - this_player->sidekick[i].ammo) * 4;
411
 
412
		this_player->sidekick[i].style = this_option->tr;
413
 
414
		this_player->sidekick[i].animation_enabled = (this_option->option == 1);
415
		this_player->sidekick[i].animation_frame = 0;
416
 
417
		this_player->sidekick[i].charge = 0;
418
		this_player->sidekick[i].charge_ticks = 20;
419
 
420
 
421
		// draw initial sidekick HUD
422
		const int y = hud_sidekick_y[twoPlayerMode ? 1 : 0][i];
423
 
424
		fill_rectangle_xy(VGAScreenSeg, 284, y, 284 + 28, y + 15, 0);
425
		if (this_option->icongr > 0)
426
			blit_sprite(VGAScreenSeg, 284, y, OPTION_SHAPES, this_option->icongr - 1);  // sidekick HUD icon
427
		draw_segmented_gauge(VGAScreenSeg, 284, y + 13, 112, 2, 2, MAX(1, this_player->sidekick[i].ammo_max / 10), this_player->sidekick[i].ammo);
428
	}
429
 
430
	VGAScreen = temp_surface;
431
 
432
	JE_drawOptionLevel();
433
}
434
 
435
void JE_drawOptionLevel( void )
436
{
437
	if (twoPlayerMode)
438
	{
439
		for (temp = 1; temp <= 3; temp++)
440
		{
441
			fill_rectangle_xy(VGAScreenSeg, 268, 127 + (temp - 1) * 6, 269, 127 + 3 + (temp - 1) * 6, 193 + ((player[1].items.sidekick_level - 100) == temp) * 11);
442
		}
443
	}
444
}
445
 
446
void JE_tyrianHalt( JE_byte code )
447
{
448
	deinit_audio();
449
	deinit_video();
450
	deinit_joysticks();
451
 
452
	/* TODO: NETWORK */
453
 
454
	free_main_shape_tables();
455
 
456
	free_sprite2s(&shapes6);
457
 
458
	for (int i = 0; i < SAMPLE_COUNT; i++)
459
	{
460
		free(digiFx[i]);
461
	}
462
 
463
	if (code != 9)
464
	{
465
		/*
466
		TODO?
467
		JE_drawANSI("exitmsg.bin");
468
		JE_gotoXY(1,22);*/
469
 
470
		JE_saveConfiguration();
471
	}
472
 
473
	/* endkeyboard; */
474
 
475
	if (code == 9)
476
	{
477
		/* OutputString('call=file0002.EXE' + #0'); TODO? */
478
	}
479
 
480
	if (code == 5)
481
	{
482
		code = 0;
483
	}
484
 
485
	if (trentWin)
486
	{
487
		printf("\n"
488
		       "\n"
489
		       "\n"
490
		       "\n"
491
		       "Sleep well, Trent, you deserve the rest.\n"
492
		       "You now have permission to borrow my ship on your next mission.\n"
493
		       "\n"
494
		       "Also, you might want to try out the YESXMAS parameter.\n"
495
		       "  Type: File0001 YESXMAS\n"
496
		       "\n"
497
		       "You'll need the 2.1 patch, though!\n"
498
		       "\n");
499
	}
500
 
501
	SDL_Quit();
502
	exit(code);
503
}
504
 
505
void JE_specialComplete( JE_byte playerNum, JE_byte specialType )
506
{
507
	nextSpecialWait = 0;
508
	switch (special[specialType].stype)
509
	{
510
		/*Weapon*/
511
		case 1:
512
			if (playerNum == 1)
513
				b = player_shot_create(0, SHOT_SPECIAL2, player[0].x, player[0].y, mouseX, mouseY, special[specialType].wpn, playerNum);
514
			else
515
				b = player_shot_create(0, SHOT_SPECIAL2, player[1].x, player[1].y, mouseX, mouseY, special[specialType].wpn, playerNum);
516
 
517
			shotRepeat[SHOT_SPECIAL] = shotRepeat[SHOT_SPECIAL2];
518
			break;
519
		/*Repulsor*/
520
		case 2:
521
			for (temp = 0; temp < ENEMY_SHOT_MAX; temp++)
522
			{
523
				if (!enemyShotAvail[temp])
524
				{
525
					if (player[0].x > enemyShot[temp].sx)
526
						enemyShot[temp].sxm--;
527
					else if (player[0].x < enemyShot[temp].sx)
528
						enemyShot[temp].sxm++;
529
 
530
					if (player[0].y > enemyShot[temp].sy)
531
						enemyShot[temp].sym--;
532
					else if (player[0].y < enemyShot[temp].sy)
533
						enemyShot[temp].sym++;
534
				}
535
			}
536
			break;
537
		/*Zinglon Blast*/
538
		case 3:
539
			zinglonDuration = 50;
540
			shotRepeat[SHOT_SPECIAL] = 100;
541
			soundQueue[7] = S_SOUL_OF_ZINGLON;
542
			break;
543
		/*Attractor*/
544
		case 4:
545
			for (temp = 0; temp < 100; temp++)
546
			{
547
				if (enemyAvail[temp] != 1 && enemy[temp].scoreitem
548
				    && enemy[temp].evalue != 0)
549
				{
550
					if (player[0].x > enemy[temp].ex)
551
						enemy[temp].exc++;
552
					else if (player[0].x < enemy[temp].ex)
553
						enemy[temp].exc--;
554
 
555
					if (player[0].y > enemy[temp].ey)
556
						enemy[temp].eyc++;
557
					else if (player[0].y < enemy[temp].ey)
558
						enemy[temp].eyc--;
559
				}
560
			}
561
			break;
562
		/*Flare*/
563
		case 5:
564
		case 6:
565
		case 7:
566
		case 8:
567
		case 9:
568
		case 10:
569
		case 11:
570
		case 16:
571
			if (flareDuration == 0)
572
				flareStart = true;
573
 
574
			specialWeaponWpn = special[specialType].wpn;
575
			linkToPlayer = false;
576
			spraySpecial = false;
577
			switch (special[specialType].stype)
578
			{
579
				case 5:
580
					specialWeaponFilter = 7;
581
					specialWeaponFreq = 2;
582
					flareDuration = 50;
583
					break;
584
				case 6:
585
					specialWeaponFilter = 1;
586
					specialWeaponFreq = 7;
587
					flareDuration = 200 + 25 * player[0].items.weapon[FRONT_WEAPON].power;
588
					break;
589
				case 7:
590
					specialWeaponFilter = 3;
591
					specialWeaponFreq = 3;
592
					flareDuration = 50 + 10 * player[0].items.weapon[FRONT_WEAPON].power;
593
					zinglonDuration = 50;
594
					shotRepeat[SHOT_SPECIAL] = 100;
595
					soundQueue[7] = S_SOUL_OF_ZINGLON;
596
					break;
597
				case 8:
598
					specialWeaponFilter = -99;
599
					specialWeaponFreq = 7;
600
					flareDuration = 10 + player[0].items.weapon[FRONT_WEAPON].power;
601
					break;
602
				case 9:
603
					specialWeaponFilter = -99;
604
					specialWeaponFreq = 8;
605
					flareDuration = 8 + 2 * player[0].items.weapon[FRONT_WEAPON].power;
606
					linkToPlayer = true;
607
					nextSpecialWait = special[specialType].pwr;
608
					break;
609
				case 10:
610
					specialWeaponFilter = -99;
611
					specialWeaponFreq = 8;
612
					flareDuration = 14 + 4 * player[0].items.weapon[FRONT_WEAPON].power;
613
					linkToPlayer = true;
614
					break;
615
				case 11:
616
					specialWeaponFilter = -99;
617
					specialWeaponFreq = special[specialType].pwr;
618
					flareDuration = 10 + 10 * player[0].items.weapon[FRONT_WEAPON].power;
619
					astralDuration = 20 + 10 * player[0].items.weapon[FRONT_WEAPON].power;
620
					break;
621
				case 16:
622
					specialWeaponFilter = -99;
623
					specialWeaponFreq = 8;
624
					flareDuration = temp2 * 16 + 8;
625
					linkToPlayer = true;
626
					spraySpecial = true;
627
					break;
628
			}
629
			break;
630
		case 12:
631
			player[playerNum-1].invulnerable_ticks = temp2 * 10;
632
 
633
			if (superArcadeMode > 0 && superArcadeMode <= SA)
634
			{
635
				shotRepeat[SHOT_SPECIAL] = 250;
636
				b = player_shot_create(0, SHOT_SPECIAL2, player[0].x, player[0].y, mouseX, mouseY, 707, 1);
637
				player[0].invulnerable_ticks = 100;
638
			}
639
			break;
640
		case 13:
641
			player[0].armor += temp2 / 4 + 1;
642
 
643
			soundQueue[3] = S_POWERUP;
644
			break;
645
		case 14:
646
			player[1].armor += temp2 / 4 + 1;
647
 
648
			soundQueue[3] = S_POWERUP;
649
			break;
650
 
651
		case 17:  // spawn left or right sidekick
652
			soundQueue[3] = S_POWERUP;
653
 
654
			if (player[0].items.sidekick[LEFT_SIDEKICK] == special[specialType].wpn)
655
			{
656
				player[0].items.sidekick[RIGHT_SIDEKICK] = special[specialType].wpn;
657
				shotMultiPos[RIGHT_SIDEKICK] = 0;
658
			}
659
			else
660
			{
661
				player[0].items.sidekick[LEFT_SIDEKICK] = special[specialType].wpn;
662
				shotMultiPos[LEFT_SIDEKICK] = 0;
663
			}
664
 
665
			JE_drawOptions();
666
			break;
667
 
668
		case 18:  // spawn right sidekick
669
			player[0].items.sidekick[RIGHT_SIDEKICK] = special[specialType].wpn;
670
 
671
			JE_drawOptions();
672
 
673
			soundQueue[4] = S_POWERUP;
674
 
675
			shotMultiPos[RIGHT_SIDEKICK] = 0;
676
			break;
677
	}
678
}
679
 
680
void JE_doSpecialShot( JE_byte playerNum, uint *armor, uint *shield )
681
{
682
	if (player[0].items.special > 0)
683
	{
684
		if (shotRepeat[SHOT_SPECIAL] == 0 && specialWait == 0 && flareDuration < 2 && zinglonDuration < 2)
685
			blit_sprite2(VGAScreen, 47, 4, shapes9, 94);
686
		else
687
			blit_sprite2(VGAScreen, 47, 4, shapes9, 93);
688
	}
689
 
690
	if (shotRepeat[SHOT_SPECIAL] > 0)
691
	{
692
		--shotRepeat[SHOT_SPECIAL];
693
	}
694
	if (specialWait > 0)
695
	{
696
		specialWait--;
697
	}
698
	temp = SFExecuted[playerNum-1];
699
	if (temp > 0 && shotRepeat[SHOT_SPECIAL] == 0 && flareDuration == 0)
700
	{
701
		temp2 = special[temp].pwr;
702
 
703
		bool can_afford = true;
704
 
705
		if (temp2 > 0)
706
		{
707
			if (temp2 < 98)  // costs some shield
708
			{
709
				if (*shield >= temp2)
710
					*shield -= temp2;
711
				else
712
					can_afford = false;
713
			}
714
			else if (temp2 == 98)  // costs all shield
715
			{
716
				if (*shield < 4)
717
					can_afford = false;
718
				temp2 = *shield;
719
				*shield = 0;
720
			}
721
			else if (temp2 == 99)  // costs half shield
722
			{
723
				temp2 = *shield / 2;
724
				*shield = temp2;
725
			}
726
			else  // costs some armor
727
			{
728
				temp2 -= 100;
729
				if (*armor > temp2)
730
					*armor -= temp2;
731
				else
732
					can_afford = false;
733
			}
734
		}
735
 
736
		shotMultiPos[SHOT_SPECIAL] = 0;
737
		shotMultiPos[SHOT_SPECIAL2] = 0;
738
 
739
		if (can_afford)
740
			JE_specialComplete(playerNum, temp);
741
 
742
		SFExecuted[playerNum-1] = 0;
743
 
744
		JE_wipeShieldArmorBars();
745
		VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
746
		JE_drawShield();
747
		JE_drawArmor();
748
		VGAScreen = game_screen; /* side-effect of game_screen */
749
	}
750
 
751
	if (playerNum == 1 && player[0].items.special > 0)
752
	{  /*Main Begin*/
753
 
754
		if (superArcadeMode > 0 && (button[2-1] || button[3-1]))
755
		{
756
			fireButtonHeld = false;
757
		}
758
		if (!button[1-1] && !(superArcadeMode != SA_NONE && (button[2-1] || button[3-1])))
759
		{
760
			fireButtonHeld = false;
761
		}
762
		else if (shotRepeat[SHOT_SPECIAL] == 0 && !fireButtonHeld && !(flareDuration > 0) && specialWait == 0)
763
		{
764
			fireButtonHeld = true;
765
			JE_specialComplete(playerNum, player[0].items.special);
766
		}
767
 
768
	}  /*Main End*/
769
 
770
	if (astralDuration > 0)
771
		astralDuration--;
772
 
773
	shotAvail[MAX_PWEAPON-1] = 0;
774
	if (flareDuration > 1)
775
	{
776
		if (specialWeaponFilter != -99)
777
		{
778
			if (levelFilter == -99 && levelBrightness == -99)
779
			{
780
				filterActive = false;
781
			}
782
			if (!filterActive)
783
			{
784
				levelFilter = specialWeaponFilter;
785
				if (levelFilter == 7)
786
				{
787
					levelBrightness = 0;
788
				}
789
				filterActive = true;
790
			}
791
 
792
			if (mt_rand() % 2 == 0)
793
				flareColChg = -1;
794
			else
795
				flareColChg = 1;
796
 
797
			if (levelFilter == 7)
798
			{
799
				if (levelBrightness < -6)
800
				{
801
					flareColChg = 1;
802
				}
803
				if (levelBrightness > 6)
804
				{
805
					flareColChg = -1;
806
				}
807
				levelBrightness += flareColChg;
808
			}
809
		}
810
 
811
		if ((signed)(mt_rand() % 6) < specialWeaponFreq)
812
		{
813
			b = MAX_PWEAPON;
814
 
815
			if (linkToPlayer)
816
			{
817
				if (shotRepeat[SHOT_SPECIAL] == 0)
818
				{
819
					b = player_shot_create(0, SHOT_SPECIAL, player[0].x, player[0].y, mouseX, mouseY, specialWeaponWpn, playerNum);
820
				}
821
			}
822
			else
823
			{
824
				b = player_shot_create(0, SHOT_SPECIAL, mt_rand() % 280, mt_rand() % 180, mouseX, mouseY, specialWeaponWpn, playerNum);
825
			}
826
 
827
			if (spraySpecial && b != MAX_PWEAPON)
828
			{
829
				playerShotData[b].shotXM = (mt_rand() % 5) - 2;
830
				playerShotData[b].shotYM = (mt_rand() % 5) - 2;
831
				if (playerShotData[b].shotYM == 0)
832
				{
833
					playerShotData[b].shotYM++;
834
				}
835
			}
836
		}
837
 
838
		flareDuration--;
839
		if (flareDuration == 1)
840
		{
841
			specialWait = nextSpecialWait;
842
		}
843
	}
844
	else if (flareStart)
845
	{
846
		flareStart = false;
847
		shotRepeat[SHOT_SPECIAL] = linkToPlayer ? 15 : 200;
848
		flareDuration = 0;
849
		if (levelFilter == specialWeaponFilter)
850
		{
851
			levelFilter = -99;
852
			levelBrightness = -99;
853
			filterActive = false;
854
		}
855
	}
856
 
857
	if (zinglonDuration > 1)
858
	{
859
		temp = 25 - abs(zinglonDuration - 25);
860
 
861
		JE_barBright(VGAScreen, player[0].x + 7 - temp,     0, player[0].x + 7 + temp,     184);
862
		JE_barBright(VGAScreen, player[0].x + 7 - temp - 2, 0, player[0].x + 7 + temp + 2, 184);
863
 
864
		zinglonDuration--;
865
		if (zinglonDuration % 5 == 0)
866
		{
867
			shotAvail[MAX_PWEAPON-1] = 1;
868
		}
869
	}
870
}
871
 
872
void JE_setupExplosion( signed int x, signed int y, signed int delta_y, unsigned int type, bool fixed_position, bool follow_player )
873
{
874
	const struct {
875
		JE_word sprite;
876
		JE_byte ttl;
877
	} explosion_data[53] /* [1..53] */ = {
878
		{ 144,  7 },
879
		{ 120, 12 },
880
		{ 190, 12 },
881
		{ 209, 12 },
882
		{ 152, 12 },
883
		{ 171, 12 },
884
		{ 133,  7 },   /*White Smoke*/
885
		{   1, 12 },
886
		{  20, 12 },
887
		{  39, 12 },
888
		{  58, 12 },
889
		{ 110,  3 },
890
		{  76,  7 },
891
		{  91,  3 },
892
/*15*/	{ 227,  3 },
893
		{ 230,  3 },
894
		{ 233,  3 },
895
		{ 252,  3 },
896
		{ 246,  3 },
897
/*20*/	{ 249,  3 },
898
		{ 265,  3 },
899
		{ 268,  3 },
900
		{ 271,  3 },
901
		{ 236,  3 },
902
/*25*/	{ 239,  3 },
903
		{ 242,  3 },
904
		{ 261,  3 },
905
		{ 274,  3 },
906
		{ 277,  3 },
907
/*30*/	{ 280,  3 },
908
		{ 299,  3 },
909
		{ 284,  3 },
910
		{ 287,  3 },
911
		{ 290,  3 },
912
/*35*/	{ 293,  3 },
913
		{ 165,  8 },   /*Coin Values*/
914
		{ 184,  8 },
915
		{ 203,  8 },
916
		{ 222,  8 },
917
		{ 168,  8 },
918
		{ 187,  8 },
919
		{ 206,  8 },
920
		{ 225, 10 },
921
		{ 169, 10 },
922
		{ 188, 10 },
923
		{ 207, 20 },
924
		{ 226, 14 },
925
		{ 170, 14 },
926
		{ 189, 14 },
927
		{ 208, 14 },
928
		{ 246, 14 },
929
		{ 227, 14 },
930
		{ 265, 14 }
931
	};
932
 
933
	if (y > -16 && y < 190)
934
	{
935
		for (int i = 0; i < MAX_EXPLOSIONS; i++)
936
		{
937
			if (explosions[i].ttl == 0)
938
			{
939
				explosions[i].x = x;
940
				explosions[i].y = y;
941
				if (type == 6)
942
				{
943
					explosions[i].y += 12;
944
					explosions[i].x += 2;
945
				} else if (type == 98)
946
				{
947
					type = 6;
948
				}
949
				explosions[i].sprite = explosion_data[type].sprite;
950
				explosions[i].ttl = explosion_data[type].ttl;
951
				explosions[i].follow_player = follow_player;
952
				explosions[i].fixed_position = fixed_position;
953
				explosions[i].delta_x = 0;
954
				explosions[i].delta_y = delta_y;
955
				break;
956
			}
957
		}
958
	}
959
}
960
 
961
void JE_setupExplosionLarge( JE_boolean enemyGround, JE_byte exploNum, JE_integer x, JE_integer y )
962
{
963
	if (y >= 0)
964
	{
965
		if (enemyGround)
966
		{
967
			JE_setupExplosion(x - 6, y - 14, 0,  2, false, false);
968
			JE_setupExplosion(x + 6, y - 14, 0,  4, false, false);
969
			JE_setupExplosion(x - 6, y,      0,  3, false, false);
970
			JE_setupExplosion(x + 6, y,      0,  5, false, false);
971
		} else {
972
			JE_setupExplosion(x - 6, y - 14, 0,  7, false, false);
973
			JE_setupExplosion(x + 6, y - 14, 0,  9, false, false);
974
			JE_setupExplosion(x - 6, y,      0,  8, false, false);
975
			JE_setupExplosion(x + 6, y,      0, 10, false, false);
976
		}
977
 
978
		bool big;
979
 
980
		if (exploNum > 10)
981
		{
982
			exploNum -= 10;
983
			big = true;
984
		}
985
		else
986
		{
987
			big = false;
988
		}
989
 
990
		if (exploNum)
991
		{
992
			for (int i = 0; i < MAX_REPEATING_EXPLOSIONS; i++)
993
			{
994
				if (rep_explosions[i].ttl == 0)
995
				{
996
					rep_explosions[i].ttl = exploNum;
997
					rep_explosions[i].delay = 2;
998
					rep_explosions[i].x = x;
999
					rep_explosions[i].y = y;
1000
					rep_explosions[i].big = big;
1001
					break;
1002
				}
1003
			}
1004
		}
1005
	}
1006
}
1007
 
1008
void JE_wipeShieldArmorBars( void )
1009
{
1010
	if (!twoPlayerMode || galagaMode)
1011
	{
1012
		fill_rectangle_xy(VGAScreenSeg, 270, 137, 278, 194 - player[0].shield * 2, 0);
1013
	}
1014
	else
1015
	{
1016
		fill_rectangle_xy(VGAScreenSeg, 270, 60 - 44, 278, 60, 0);
1017
		fill_rectangle_xy(VGAScreenSeg, 270, 194 - 44, 278, 194, 0);
1018
	}
1019
	if (!twoPlayerMode || galagaMode)
1020
	{
1021
		fill_rectangle_xy(VGAScreenSeg, 307, 137, 315, 194 - player[0].armor * 2, 0);
1022
	}
1023
	else
1024
	{
1025
		fill_rectangle_xy(VGAScreenSeg, 307, 60 - 44, 315, 60, 0);
1026
		fill_rectangle_xy(VGAScreenSeg, 307, 194 - 44, 315, 194, 0);
1027
	}
1028
}
1029
 
1030
JE_byte JE_playerDamage( JE_byte temp,
1031
                         Player *this_player )
1032
{
1033
	int playerDamage = 0;
1034
	soundQueue[7] = S_SHIELD_HIT;
1035
 
1036
	/* Player Damage Routines */
1037
	if (this_player->shield < temp)
1038
	{
1039
		playerDamage = temp;
1040
		temp -= this_player->shield;
1041
		this_player->shield = 0;
1042
 
1043
		if (temp > 0)
1044
		{
1045
			/*Through Shields - Now Armor */
1046
 
1047
			if (this_player->armor < temp)
1048
			{
1049
				temp -= this_player->armor;
1050
				this_player->armor = 0;
1051
 
1052
				if (this_player->is_alive && !youAreCheating)
1053
				{
1054
					levelTimer = false;
1055
					this_player->is_alive = false;
1056
					this_player->exploding_ticks = 60;
1057
					levelEnd = 40;
1058
					tempVolume = tyrMusicVolume;
1059
					soundQueue[1] = S_EXPLOSION_22;
1060
				}
1061
			}
1062
			else
1063
			{
1064
				this_player->armor -= temp;
1065
				soundQueue[7] = S_HULL_HIT;
1066
			}
1067
		}
1068
	}
1069
	else
1070
	{
1071
		this_player->shield -= temp;
1072
 
1073
		JE_setupExplosion(this_player->x - 17, this_player->y - 12, 0, 14, false, !twoPlayerMode);
1074
		JE_setupExplosion(this_player->x - 5 , this_player->y - 12, 0, 15, false, !twoPlayerMode);
1075
		JE_setupExplosion(this_player->x + 7 , this_player->y - 12, 0, 16, false, !twoPlayerMode);
1076
		JE_setupExplosion(this_player->x + 19, this_player->y - 12, 0, 17, false, !twoPlayerMode);
1077
 
1078
		JE_setupExplosion(this_player->x - 17, this_player->y + 2, 0,  18, false, !twoPlayerMode);
1079
		JE_setupExplosion(this_player->x + 19, this_player->y + 2, 0,  19, false, !twoPlayerMode);
1080
 
1081
		JE_setupExplosion(this_player->x - 17, this_player->y + 16, 0, 20, false, !twoPlayerMode);
1082
		JE_setupExplosion(this_player->x - 5 , this_player->y + 16, 0, 21, false, !twoPlayerMode);
1083
		JE_setupExplosion(this_player->x + 7 , this_player->y + 16, 0, 22, false, !twoPlayerMode);
1084
	}
1085
 
1086
	JE_wipeShieldArmorBars();
1087
	VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
1088
	JE_drawShield();
1089
	JE_drawArmor();
1090
	VGAScreen = game_screen; /* side-effect of game_screen */
1091
 
1092
	return playerDamage;
1093
}
1094
 
1095
JE_word JE_portConfigs( void )
1096
{
1097
	const uint player_index = twoPlayerMode ? 1 : 0;
1098
	return tempW = weaponPort[player[player_index].items.weapon[REAR_WEAPON].id].opnum;
1099
}
1100
 
1101
void JE_drawShield( void )
1102
{
1103
	if (twoPlayerMode && !galagaMode)
1104
	{
1105
		for (uint i = 0; i < COUNTOF(player); ++i)
1106
			JE_dBar3(VGAScreen, 270, 60 + 134 * i, roundf(player[i].shield * 0.8f), 144);
1107
	}
1108
	else
1109
	{
1110
		JE_dBar3(VGAScreen, 270, 194, player[0].shield, 144);
1111
		if (player[0].shield != player[0].shield_max)
1112
		{
1113
			const uint y = 193 - (player[0].shield_max * 2);
1114
			JE_rectangle(VGAScreen, 270, y, 278, y, 68); /*  SEGa000 */
1115
		}
1116
	}
1117
}
1118
 
1119
void JE_drawArmor( void )
1120
{
1121
	for (uint i = 0; i < COUNTOF(player); ++i)
1122
		if (player[i].armor > 28)
1123
			player[i].armor = 28;
1124
 
1125
	if (twoPlayerMode && !galagaMode)
1126
	{
1127
		for (uint i = 0; i < COUNTOF(player); ++i)
1128
			JE_dBar3(VGAScreen, 307, 60 + 134 * i, roundf(player[i].armor * 0.8f), 224);
1129
	}
1130
	else
1131
	{
1132
		JE_dBar3(VGAScreen, 307, 194, player[0].armor, 224);
1133
	}
1134
}
1135
 
1136
void JE_doSP( JE_word x, JE_word y, JE_word num, JE_byte explowidth, JE_byte color ) /* superpixels */
1137
{
1138
	for (temp = 0; temp < num; temp++)
1139
	{
1140
		JE_real tempr = mt_rand_lt1() * (2 * M_PI);
1141
		signed int tempy = roundf(cosf(tempr) * mt_rand_1() * explowidth);
1142
		signed int tempx = roundf(sinf(tempr) * mt_rand_1() * explowidth);
1143
 
1144
		if (++last_superpixel >= MAX_SUPERPIXELS)
1145
			last_superpixel = 0;
1146
		superpixels[last_superpixel].x = tempx + x;
1147
		superpixels[last_superpixel].y = tempy + y;
1148
		superpixels[last_superpixel].delta_x = tempx;
1149
		superpixels[last_superpixel].delta_y = tempy + 1;
1150
		superpixels[last_superpixel].color = color;
1151
		superpixels[last_superpixel].z = 15;
1152
	}
1153
}
1154
 
1155
void JE_drawSP( void )
1156
{
1157
	for (int i = MAX_SUPERPIXELS; i--; )
1158
	{
1159
		if (superpixels[i].z)
1160
		{
1161
			superpixels[i].x += superpixels[i].delta_x;
1162
			superpixels[i].y += superpixels[i].delta_y;
1163
 
1164
			if (superpixels[i].x < (unsigned)VGAScreen->w && superpixels[i].y < (unsigned)VGAScreen->h)
1165
			{
1166
				Uint8 *s = (Uint8 *)VGAScreen->pixels; /* screen pointer, 8-bit specific */
1167
				s += superpixels[i].y * VGAScreen->pitch;
1168
				s += superpixels[i].x;
1169
 
1170
				*s = (((*s & 0x0f) + superpixels[i].z) >> 1) + superpixels[i].color;
1171
				if (superpixels[i].x > 0)
1172
					*(s - 1) = (((*(s - 1) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color;
1173
				if (superpixels[i].x < VGAScreen->w - 1u)
1174
					*(s + 1) = (((*(s + 1) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color;
1175
				if (superpixels[i].y > 0)
1176
					*(s - VGAScreen->pitch) = (((*(s - VGAScreen->pitch) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color;
1177
				if (superpixels[i].y < VGAScreen->h - 1u)
1178
					*(s + VGAScreen->pitch) = (((*(s + VGAScreen->pitch) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color;
1179
			}
1180
 
1181
			superpixels[i].z--;
1182
		}
1183
	}
1184
}
1185