2
* OpenTyrian: A modern cross-platform port of Tyrian
3
* Copyright (C) 2007-2013 The OpenTyrian Development Team
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.
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.
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.
25
// I'm pretty sure the last extra entry is never used.
26
PlayerShotDataType playerShotData[MAX_PWEAPON + 1]; /* [1..MaxPWeapon+1] */
27
JE_byte shotAvail[MAX_PWEAPON]; /* [1..MaxPWeapon] */ /*0:Avail 1-255:Duration left*/
29
void simulate_player_shots( void )
31
/* Player Shot Images */
32
for (int z = 0; z < MAX_PWEAPON; z++)
34
if (shotAvail[z] != 0)
37
if (z != MAX_PWEAPON - 1)
39
PlayerShotDataType* shot = &playerShotData[z];
41
shot->shotXM += shot->shotXC;
43
if (shot->shotXM <= 100)
44
shot->shotX += shot->shotXM;
46
shot->shotYM += shot->shotYC;
47
shot->shotY += shot->shotYM;
49
if (shot->shotYM > 100)
52
shot->shotY += player[0].delta_y_shot_move;
55
if (shot->shotComplicated != 0)
57
shot->shotDevX += shot->shotDirX;
58
shot->shotX += shot->shotDevX;
60
if (abs(shot->shotDevX) == shot->shotCirSizeX)
61
shot->shotDirX = -shot->shotDirX;
63
shot->shotDevY += shot->shotDirY;
64
shot->shotY += shot->shotDevY;
66
if (abs(shot->shotDevY) == shot->shotCirSizeY)
67
shot->shotDirY = -shot->shotDirY;
68
/*Double Speed Circle Shots - add a second copy of above loop*/
71
int tempShotX = shot->shotX;
72
int tempShotY = shot->shotY;
74
if (shot->shotX < 0 || shot->shotX > 140 ||
75
shot->shotY < 0 || shot->shotY > 170)
78
goto draw_player_shot_loop_end;
81
/* if (shot->shotTrail != 255)
83
if (shot->shotTrail == 98)
85
JE_setupExplosion(shot->shotX - shot->shotXM, shot->shotY - shot->shotYM, shot->shotTrail);
87
JE_setupExplosion(shot->shotX, shot->shotY, shot->shotTrail);
91
JE_word anim_frame = shot->shotGr + shot->shotAni;
92
if (++shot->shotAni == shot->shotAniMax)
95
if (anim_frame < 6000)
97
if (anim_frame > 1000)
98
anim_frame = anim_frame % 1000;
100
blit_sprite2(VGAScreen, tempShotX+1, tempShotY, shapesW2, anim_frame - 500);
102
blit_sprite2(VGAScreen, tempShotX+1, tempShotY, shapesC1, anim_frame);
106
draw_player_shot_loop_end:
112
static const JE_word linkMultiGr[17] /* [0..16] */ =
113
{77,221,183,301,1,282,164,202,58,201,163,281,39,300,182,220,77};
114
static const JE_word linkSonicGr[17] /* [0..16] */ =
115
{85,242,131,303,47,284,150,223,66,224,149,283,9,302,130,243,85};
116
static const JE_word linkMult2Gr[17] /* [0..16] */ =
117
{78,299,295,297,2,278,276,280,59,279,275,277,40,296,294,298,78};
119
void player_shot_set_direction( JE_integer shot_id, uint weapon_id, JE_real direction )
121
PlayerShotDataType* shot = &playerShotData[shot_id];
123
shot->shotXM = -roundf(sinf(direction) * shot->shotYM);
124
shot->shotYM = -roundf(cosf(direction) * shot->shotYM);
126
// Some weapons have sprites for each direction, use those.
134
rounded_dir = roundf(direction * (16 / (2 * M_PI))); /*16 directions*/
135
shot->shotGr = linkMultiGr[rounded_dir];
140
rounded_dir = roundf(direction * (16 / (2 * M_PI))); /*16 directions*/
141
shot->shotGr = linkSonicGr[rounded_dir];
146
if (direction > M_PI_2 && direction < M_PI + M_PI_2)
153
rounded_dir = roundf(direction * (16 / (2 * M_PI))); /*16 directions*/
154
shot->shotGr = linkMult2Gr[rounded_dir];
159
bool player_shot_move_and_draw(
160
int shot_id, bool* out_is_special,
161
int* out_shotx, int* out_shoty,
162
JE_integer* out_shot_damage, JE_byte* out_blast_filter,
163
JE_byte* out_chain, JE_byte* out_playerNum,
164
JE_word* out_special_radiusw, JE_word* out_special_radiush )
166
PlayerShotDataType* shot = &playerShotData[shot_id];
168
shotAvail[shot_id]--;
169
if (shot_id != MAX_PWEAPON - 1)
171
shot->shotXM += shot->shotXC;
172
shot->shotX += shot->shotXM;
173
JE_integer tmp_shotXM = shot->shotXM;
175
if (shot->shotXM > 100)
177
if (shot->shotXM == 101)
180
shot->shotX += player[shot->playerNumber-1].delta_x_shot_move;
181
shot->shotY += player[shot->playerNumber-1].delta_y_shot_move;
186
shot->shotX += player[shot->playerNumber-1].delta_x_shot_move;
190
shot->shotYM += shot->shotYC;
191
shot->shotY += shot->shotYM;
193
if (shot->shotYM > 100)
196
shot->shotY += player[shot->playerNumber-1].delta_y_shot_move;
199
if (shot->shotComplicated != 0)
201
shot->shotDevX += shot->shotDirX;
202
shot->shotX += shot->shotDevX;
204
if (abs(shot->shotDevX) == shot->shotCirSizeX)
205
shot->shotDirX = -shot->shotDirX;
207
shot->shotDevY += shot->shotDirY;
208
shot->shotY += shot->shotDevY;
210
if (abs(shot->shotDevY) == shot->shotCirSizeY)
211
shot->shotDirY = -shot->shotDirY;
213
/*Double Speed Circle Shots - add a second copy of above loop*/
216
*out_shotx = shot->shotX;
217
*out_shoty = shot->shotY;
219
if (shot->shotX < -34 || shot->shotX > 290 ||
220
shot->shotY < -15 || shot->shotY > 190)
222
shotAvail[shot_id] = 0;
226
if (shot->shotTrail != 255)
228
if (shot->shotTrail == 98)
229
JE_setupExplosion(shot->shotX - shot->shotXM, shot->shotY - shot->shotYM, 0, shot->shotTrail, false, false);
231
JE_setupExplosion(shot->shotX, shot->shotY, 0, shot->shotTrail, false, false);
234
if (shot->aimAtEnemy != 0)
236
if (--shot->aimDelay == 0)
238
shot->aimDelay = shot->aimDelayMax;
240
if (enemyAvail[shot->aimAtEnemy - 1] != 1)
242
if (shot->shotX < enemy[shot->aimAtEnemy - 1].ex)
247
if (shot->shotY < enemy[shot->aimAtEnemy - 1].ey)
254
if (shot->shotXM > 0)
262
JE_word sprite_frame = shot->shotGr + shot->shotAni;
263
if (++shot->shotAni == shot->shotAniMax)
266
*out_shot_damage = shot->shotDmg;
267
*out_blast_filter = shot->shotBlastFilter;
268
*out_chain = shot->chainReaction;
269
*out_playerNum = shot->playerNumber;
271
*out_is_special = sprite_frame > 60000;
275
blit_sprite_blend(VGAScreen, *out_shotx+1, *out_shoty, OPTION_SHAPES, sprite_frame - 60001);
277
*out_special_radiusw = sprite(OPTION_SHAPES, sprite_frame - 60001)->width / 2;
278
*out_special_radiush = sprite(OPTION_SHAPES, sprite_frame - 60001)->height / 2;
282
if (sprite_frame > 1000)
284
JE_doSP(*out_shotx+1 + 6, *out_shoty + 6, 5, 3, (sprite_frame / 1000) << 4);
285
sprite_frame = sprite_frame % 1000;
287
if (sprite_frame > 500)
289
if (background2 && *out_shoty + shadowYDist < 190 && tmp_shotXM < 100)
290
blit_sprite2_darken(VGAScreen, *out_shotx+1, *out_shoty + shadowYDist, shapesW2, sprite_frame - 500);
291
blit_sprite2(VGAScreen, *out_shotx+1, *out_shoty, shapesW2, sprite_frame - 500);
295
if (background2 && *out_shoty + shadowYDist < 190 && tmp_shotXM < 100)
296
blit_sprite2_darken(VGAScreen, *out_shotx+1, *out_shoty + shadowYDist, shapesC1, sprite_frame);
297
blit_sprite2(VGAScreen, *out_shotx+1, *out_shoty, shapesC1, sprite_frame);
305
JE_integer player_shot_create( JE_word portNum, uint bay_i, JE_word PX, JE_word PY, JE_word mouseX, JE_word mouseY, JE_word wpNum, JE_byte playerNum )
307
static const JE_byte soundChannel[11] /* [1..11] */ = {0, 2, 4, 4, 2, 2, 5, 5, 1, 4, 1};
310
if (portNum > PORT_NUM || wpNum <= 0 || wpNum > WEAP_NUM)
313
const JE_WeaponType* weapon = &weapons[wpNum];
315
if (power < weaponPort[portNum].poweruse)
317
power -= weaponPort[portNum].poweruse;
319
if (weapon->sound > 0)
320
soundQueue[soundChannel[bay_i]] = weapon->sound;
324
for (int multi_i = 1; multi_i <= weapon->multi; multi_i++)
326
for (shot_id = 0; shot_id < MAX_PWEAPON; shot_id++)
327
if (shotAvail[shot_id] == 0)
329
if (shot_id == MAX_PWEAPON)
332
if (shotMultiPos[bay_i] == weapon->max || shotMultiPos[bay_i] > 8)
333
shotMultiPos[bay_i] = 1;
335
shotMultiPos[bay_i]++;
337
PlayerShotDataType* shot = &playerShotData[shot_id];
338
shot->chainReaction = 0;
340
shot->playerNumber = playerNum;
344
shot->shotComplicated = weapon->circlesize != 0;
346
if (weapon->circlesize == 0)
352
shot->shotCirSizeX = 0;
353
shot->shotCirSizeY = 0;
357
JE_byte circsize = weapon->circlesize;
361
JE_byte circsize_mod20 = circsize % 20;
362
shot->shotCirSizeX = circsize_mod20;
363
shot->shotDevX = circsize_mod20 >> 1;
365
circsize = circsize / 20;
366
shot->shotCirSizeY = circsize;
367
shot->shotDevY = circsize >> 1;
371
shot->shotCirSizeX = circsize;
372
shot->shotCirSizeY = circsize;
373
shot->shotDevX = circsize >> 1;
374
shot->shotDevY = circsize >> 1;
380
shot->shotTrail = weapon->trail;
382
if (weapon->attack[shotMultiPos[bay_i]-1] > 99 && weapon->attack[shotMultiPos[bay_i]-1] < 250)
384
shot->chainReaction = weapon->attack[shotMultiPos[bay_i]-1] - 100;
389
shot->shotDmg = weapon->attack[shotMultiPos[bay_i]-1];
392
shot->shotBlastFilter = weapon->shipblastfilter;
394
JE_integer tmp_by = weapon->by[shotMultiPos[bay_i]-1];
396
/*Note: Only front selection used for player shots...*/
398
shot->shotX = PX + weapon->bx[shotMultiPos[bay_i]-1];
400
shot->shotY = PY + tmp_by;
401
shot->shotYC = -weapon->acceleration;
402
shot->shotXC = weapon->accelerationx;
404
shot->shotXM = weapon->sx[shotMultiPos[bay_i]-1];
406
// Not sure what this field does exactly.
407
JE_byte del = weapon->del[shotMultiPos[bay_i]-1];
415
shot->shotGr = weapon->sg[shotMultiPos[bay_i]-1];
416
if (shot->shotGr == 0)
417
shotAvail[shot_id] = 0;
419
shotAvail[shot_id] = del;
421
if (del > 100 && del < 120)
422
shot->shotAniMax = (del - 100 + 1);
424
shot->shotAniMax = weapon->weapani + 1;
426
if (del == 99 || del == 98)
428
tmp_by = PX - mouseX;
433
shot->shotXM += tmp_by;
436
if (del == 99 || del == 100)
438
tmp_by = PY - mouseY - weapon->sy[shotMultiPos[bay_i]-1];
443
shot->shotYM = tmp_by;
445
else if (weapon->sy[shotMultiPos[bay_i]-1] == 98)
450
else if (weapon->sy[shotMultiPos[bay_i]-1] > 100)
452
shot->shotYM = weapon->sy[shotMultiPos[bay_i]-1];
453
shot->shotY -= player[shot->playerNumber-1].delta_y_shot_move;
457
shot->shotYM = -weapon->sy[shotMultiPos[bay_i]-1];
460
if (weapon->sx[shotMultiPos[bay_i]-1] > 100)
462
shot->shotXM = weapon->sx[shotMultiPos[bay_i]-1];
463
shot->shotX -= player[shot->playerNumber-1].delta_x_shot_move;
464
if (shot->shotXM == 101)
465
shot->shotY -= player[shot->playerNumber-1].delta_y_shot_move;
469
if (weapon->aim > 5) /*Guided Shot*/
471
uint best_dist = 65000;
472
JE_byte closest_enemy = 0;
473
/*Find Closest Enemy*/
474
for (x = 0; x < 100; x++)
476
if (enemyAvail[x] != 1 && !enemy[x].scoreitem)
478
y = abs(enemy[x].ex - shot->shotX) + abs(enemy[x].ey - shot->shotY);
482
closest_enemy = x + 1;
486
shot->aimAtEnemy = closest_enemy;
488
shot->aimDelayMax = weapon->aim - 5;
492
shot->aimAtEnemy = 0;
495
shotRepeat[bay_i] = weapon->shotrepeat;