205 lines
4.8 KiB
C++
205 lines
4.8 KiB
C++
/*
|
|
Copyright (C) 2003 Parallel Realities
|
|
Copyright (C) 2011, 2012 Guus Sliepen
|
|
Copyright (C) 2015, 2016 onpon4 <onpon4@riseup.net>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 3
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "Starfighter.h"
|
|
|
|
void bullet_add(object *theWeapon, object *attacker, int y, int dy)
|
|
{
|
|
object *bullet;
|
|
int imageIndex;
|
|
int tempX, tempY, steps;
|
|
|
|
bullet = new object;
|
|
|
|
if (attacker == &player)
|
|
game.shots++;
|
|
|
|
bullet->next = NULL;
|
|
bullet->active = true;
|
|
bullet->x = attacker->x + (attacker->image[0]->w / 2) -
|
|
(theWeapon->image[0]->w * attacker->face);
|
|
bullet->y = attacker->y + y;
|
|
bullet->flags = theWeapon->flags;
|
|
bullet->shield = 300; // bullets live for (approximately) 5 seconds
|
|
|
|
// Timed explosions live between 1 and 3 seconds
|
|
if (bullet->flags & WF_TIMEDEXPLOSION)
|
|
bullet->shield = 60 + ((rand() % 3) * 60);
|
|
|
|
if (attacker->face == 0)
|
|
{
|
|
bullet->dx = theWeapon->speed;
|
|
if ((game.area == MISN_ELLESH) ||
|
|
(game.area == MISN_MARS))
|
|
bullet->dx += fabsf(engine.ssx + engine.smx);
|
|
}
|
|
else
|
|
{
|
|
bullet->dx = -theWeapon->speed;
|
|
}
|
|
|
|
if (bullet->flags & WF_VARIABLE_SPEED)
|
|
{
|
|
bullet->dx = RANDRANGE(100, 200) / 10;
|
|
if (attacker->face == 1)
|
|
bullet->dx = -bullet->dx;
|
|
}
|
|
|
|
bullet->dy = dy;
|
|
|
|
if (bullet->flags & WF_SCATTER)
|
|
{
|
|
bullet->dy = RANDRANGE(-200, 200) / 200;
|
|
}
|
|
|
|
if (attacker->flags & FL_WEAPCO)
|
|
bullet->flags |= WF_WEAPCO;
|
|
else
|
|
bullet->flags |= WF_FRIEND;
|
|
|
|
bullet->owner = attacker->owner;
|
|
|
|
bullet->id = theWeapon->id;
|
|
|
|
bullet->damage = theWeapon->damage;
|
|
|
|
if (bullet->id == WT_CHARGER)
|
|
{
|
|
if (game.difficulty == DIFFICULTY_ORIGINAL)
|
|
bullet->damage = attacker->ammo[1];
|
|
else
|
|
bullet->damage = attacker->ammo[1] / 2;
|
|
|
|
if (bullet->damage < 15)
|
|
{
|
|
bullet->damage = 1;
|
|
bullet->id = WT_PLASMA;
|
|
}
|
|
}
|
|
|
|
bullet->target = NULL;
|
|
|
|
if (attacker->flags & FL_FRIEND)
|
|
imageIndex = 0;
|
|
else
|
|
imageIndex = 1;
|
|
|
|
// Use the enemy's images if applicable
|
|
if (bullet->id != WT_ROCKET)
|
|
bullet->image[0] = theWeapon->image[imageIndex];
|
|
else
|
|
bullet->image[0] = theWeapon->image[attacker->face];
|
|
|
|
if (bullet->flags & WF_AIMED)
|
|
{
|
|
tempX = (int)fabsf(attacker->target->x - attacker->x);
|
|
tempY = (int)fabsf(attacker->target->y - attacker->y);
|
|
steps = MAX(tempX, tempY);
|
|
|
|
if (steps < 12)
|
|
steps = 12;
|
|
|
|
if (!(bullet->flags & WF_TIMEDEXPLOSION))
|
|
steps /= 8;
|
|
else
|
|
steps /= 6 + (rand() % 6);
|
|
|
|
tempX = (int)(attacker->target->x - attacker->x);
|
|
tempY = (int)(attacker->target->y - attacker->y);
|
|
|
|
bullet->dx = tempX / steps;
|
|
bullet->dy = tempY / steps;
|
|
}
|
|
|
|
if (attacker->classDef == CD_ASTEROID)
|
|
{
|
|
bullet->dx = RANDRANGE(-20, 20);
|
|
bullet->dy = RANDRANGE(-20, 20);
|
|
bullet->image[0] = gfx_sprites[SP_SMALL_EXPLOSION];
|
|
}
|
|
|
|
engine.bulletTail->next = bullet;
|
|
engine.bulletTail = bullet;
|
|
}
|
|
|
|
/*
|
|
Used for homing missiles. When a missile is active and it is told to home in
|
|
on an enemy, it will attempt to randomly grab one every frame if it does not
|
|
already have a target. If the target it is currently chasing is killed, it will
|
|
begin to look for a new one (done in doBullets()). The homing missile will make
|
|
one attempt per call (one call per frame) to find a suitable target. If the target
|
|
it picks is dead or outside the screen range, then it returns NULL. A suitable
|
|
target will be returned as the object address.
|
|
*/
|
|
object *bullet_getTarget(object *bullet)
|
|
{
|
|
int i;
|
|
|
|
if (bullet->owner->flags & FL_WEAPCO)
|
|
{
|
|
i = (rand() % 10);
|
|
|
|
if (i < 1)
|
|
return &player;
|
|
}
|
|
|
|
i = rand() % ALIEN_MAX;
|
|
|
|
if ((aliens[i].shield < 1) || (!aliens[i].active))
|
|
return NULL;
|
|
|
|
if (aliens[i].flags & FL_IMMORTAL)
|
|
return NULL;
|
|
|
|
if ((bullet->owner->flags & FL_WEAPCO) && (aliens[i].flags & FL_WEAPCO))
|
|
return NULL;
|
|
|
|
if ((bullet->owner->flags & FL_FRIEND) && (aliens[i].flags & FL_FRIEND))
|
|
return NULL;
|
|
|
|
if (abs((int)bullet->x - (int)aliens[i].target->x) > 800)
|
|
return NULL;
|
|
|
|
if (abs((int)bullet->y - (int)aliens[i].target->y) > 200)
|
|
return NULL;
|
|
|
|
return &aliens[i];
|
|
}
|
|
|
|
bool bullet_collision(object *bullet, object *ship)
|
|
{
|
|
float x0 = bullet->x;
|
|
float y0 = bullet->y;
|
|
float w0 = bullet->image[0]->w;
|
|
float h0 = bullet->image[0]->h;
|
|
|
|
float x2 = ship->x;
|
|
float y2 = ship->y;
|
|
float w1 = ship->image[0]->w;
|
|
float h1 = ship->image[0]->h;
|
|
|
|
float x1 = x0 + w0;
|
|
float y1 = y0 + h0;
|
|
|
|
float x3 = x2 + w1;
|
|
float y3 = y2 + h1;
|
|
|
|
return !(x1<x2 || x3<x0 || y1<y2 || y3<y0);
|
|
}
|