/* Copyright (C) 2003 Parallel Realities Copyright (C) 2011, 2012 Guus Sliepen Copyright (C) 2015 Julian Marchant 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 . */ #include "Starfighter.h" void bullet_add(object *theWeapon, object *attacker, int y, int dy) { object *bullet; signed char imageIndex; int tempX, tempY, steps; bullet = new object; if (attacker == &player) currentGame.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 ((currentGame.area == MISN_ELLESH) || (currentGame.area == MISN_MARS)) bullet->dx += fabsf(engine.ssx + engine.smx); } else { bullet->dx = (0 - theWeapon->speed); } if (bullet->flags & WF_VARIABLE_SPEED) { bullet->dx = RANDRANGE(100, 200); bullet->dx /= 10; if (attacker->face == 1) bullet->dx = 0 - bullet->dx; } bullet->dy = dy; if (bullet->flags & WF_SCATTER) { bullet->dy = RANDRANGE(-200, 200); if (bullet->dy != 0) bullet->dy /= 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) { 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] = shape[4]; } 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]; }