starfighter/code/collectable.cpp

431 lines
11 KiB
C++

/*
Copyright (C) 2003 Parallel Realities
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 2
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "collectable.h"
/*
Create a new collectable item based on supplied arguments.
*/
void addCollectable(float x, float y, int type, int value, int life)
{
if (type == P_ANYTHING)
{
type = P_CASH;
int r = rand() % 9;
switch (r)
{
case 0:
type = P_PLASMA_AMMO;
break;
case 1:
type = P_SHIELD;
break;
case 2:
type = P_ROCKET;
value /= 10;
break;
}
}
else if (type == P_WEAPONS)
{
type = P_PLASMA_RATE;
int r = rand() % 61;
if (r <= 19)
type = P_PLASMA_DAMAGE;
else if (r <= 39)
type = P_PLASMA_SHOT;
else if (r <= 59)
type = P_PLASMA_RATE;
else
type = P_SUPER;
}
if (type == P_SUPER)
value = 1;
/*
Cash is rare on interceptions. Stops people from point leeching(!)
*/
if ((currentGame.area == MAX_MISSIONS - 1) && (type == P_CASH))
{
if (rand() % 10 > 0)
return;
}
if (value == 0)
return; // don't bother!
// If the player has a charge cannon or a laser cannon, don't give them
// rockets. Causes problems otherwise :)
if (type == P_ROCKET)
{
if ((player.weaponType[1] == W_CHARGER) || (player.weaponType[1] == W_LASER))
{
type = P_CASH;
}
}
collectables *collectable = new collectables;
collectable->next = NULL;
collectable->active = 1;
collectable->x = x;
collectable->y = y;
collectable->dx = Math::rrand(-100, 100);
if (collectable->dx != 0)
collectable->dx /= 100;
collectable->dy = Math::rrand(-100, 100);
if (collectable->dy != 0)
collectable->dy /= 100;
collectable->type = type;
collectable->value = value;
collectable->life = life;
switch(type)
{
case P_CASH:
collectable->image = graphics.shape[24];
break;
case P_ROCKET:
collectable->image = graphics.shape[49];
break;
case P_PLASMA_AMMO:
collectable->image = graphics.shape[25];
break;
case P_SHIELD:
collectable->image = graphics.shape[26];
break;
case P_PLASMA_SHOT:
collectable->image = graphics.shape[27];
break;
case P_PLASMA_RATE:
collectable->image = graphics.shape[28];
break;
case P_PLASMA_DAMAGE:
collectable->image = graphics.shape[29];
break;
case P_CARGO:
collectable->image = graphics.shape[32];
break;
case P_SUPER:
collectable->image = graphics.shape[50];
break;
case P_MINE:
collectable->image = graphics.shape[31];
break;
case P_SLAVES:
case P_ESCAPEPOD:
collectable->image = graphics.shape[45];
break;
case P_ORE:
collectable->image = graphics.shape[46 + rand() % 3];
break;
}
engine.collectableTail->next = collectable;
engine.collectableTail = collectable;
}
void explodeMine(collectables *collectable)
{
if ((collectable->x >= 0) && (collectable->x <= 800) && (collectable->y >= 0) && (collectable->y <= 600))
playSound(SFX_EXPLOSION);
for (int i = 0 ; i < 10 ; i++)
addExplosion(collectable->x + rand() % 25 - rand() % 25, collectable->y + rand() % 25 - rand() % 25, E_BIG_EXPLOSION);
if (checkPlayerShockDamage(collectable->x, collectable->y, 50))
setInfoLine("Warning: Mine damage to shield!!", FONT_RED);
}
void checkMineBulletCollisions(object *bullet)
{
collectables *collectable = engine.collectableHead;
collectables *prevCollectable = engine.collectableHead;
engine.collectableTail = engine.collectableHead;
while (collectable->next != NULL)
{
collectable = collectable->next;
if (collectable->type == P_MINE)
{
if (Collision::collision(collectable, bullet))
{
collectable->active = 0;
if (bullet->id != WT_CHARGER)
{
bullet->active = 0;
}
else
{
bullet->shield--;
if (bullet->shield < 0)
bullet->active = 0;
}
if (bullet->owner == &player)
{
currentGame.minesKilled++;
currentGame.hits++;
}
}
}
if (collectable->active == 1)
{
prevCollectable = collectable;
engine.collectableTail = collectable;
}
else
{
explodeMine(collectable);
prevCollectable->next = collectable->next;
delete collectable;
collectable = prevCollectable;
}
}
}
/*
Loops through the currently active collectables (in a linked list). The collectable
will travel in the direction that was defined when it was made. Its life will decreased
whilst it remains active. It will be removed if the player touches it or if its life
reaches 0. When it is picked up, depending on the type of collectable it is, mission requirements
will be updated. Information will be displayed and appropriate player variables altered.
*/
void doCollectables()
{
collectables *collectable = engine.collectableHead;
collectables *prevCollectable = engine.collectableHead;
engine.collectableTail = engine.collectableHead;
while (collectable->next != NULL)
{
collectable = collectable->next;
if (collectable->active == 1)
{
if ((collectable->x + collectable->image->w > 0) && (collectable->x < 800) && (collectable->y + collectable->image->h > 0) && (collectable->y < 600))
graphics.blit(collectable->image, (int)collectable->x, (int)collectable->y);
collectable->x += engine.ssx;
collectable->y += engine.ssy;
collectable->x += collectable->dx;
collectable->y += collectable->dy;
collectable->life--;
if ((player.shield > 0) && (Collision::collision(collectable, &player)))
{
char temp[40];
switch(collectable->type)
{
case P_CASH:
currentGame.cash += collectable->value;
currentGame.cashEarned += collectable->value;
sprintf(temp, "Got $%d ", collectable->value);
break;
case P_ROCKET:
Math::limitCharAdd(&player.ammo[1], collectable->value, 0, currentGame.maxRocketAmmo);
if (player.ammo[1] == currentGame.maxRocketAmmo)
sprintf(temp, "Rocket Ammo at Maximum");
else
{
if (collectable->value > 1)
sprintf(temp, "Got %d rockets", collectable->value);
else
sprintf(temp, "Got a rocket");
}
currentGame.rocketPickups += collectable->value;
break;
case P_SHIELD:
Math::limitInt(&(player.shield += 10), 0, player.maxShield);
currentGame.shieldPickups ++;
sprintf(temp, "Restored 10 shield points");
break;
case P_PLASMA_RATE:
Math::limitCharAdd(&weapon[1].reload[0], -2, currentGame.maxPlasmaRate, 15);
player.weaponType[0] = 1;
if (player.ammo[0] < 50)
player.ammo[0] = 50;
Math::limitChar(&(player.ammo[0]), 0, currentGame.maxPlasmaAmmo);
if (weapon[1].reload[0] == currentGame.maxPlasmaRate)
sprintf(temp, "Firing Rate at Maximum");
else
sprintf(temp, "Firing rate increased");
currentGame.powerups++;
break;
case P_PLASMA_SHOT:
Math::limitCharAdd(&weapon[1].ammo[0], 1, 1, currentGame.maxPlasmaOutput);
if (player.ammo[0] < 50)
player.ammo[0] = 50;
Math::limitChar(&(player.ammo[0]), 0, currentGame.maxPlasmaAmmo);
if (weapon[1].ammo[0] == currentGame.maxPlasmaOutput)
sprintf(temp, "Plasma output at Maximum");
else
sprintf(temp, "Plasma output increased");
player.weaponType[0] = 1;
currentGame.powerups++;
break;
case P_PLASMA_DAMAGE:
Math::limitCharAdd(&weapon[1].damage, 1, 1, currentGame.maxPlasmaDamage);
if (player.ammo[0] < 50)
player.ammo[0] = 50;
Math::limitChar(&(player.ammo[0]), 0, currentGame.maxPlasmaAmmo);
if (weapon[1].damage == currentGame.maxPlasmaDamage)
sprintf(temp, "Plasma damage at Maximum");
else
sprintf(temp, "Plasma damage increased");
player.weaponType[0] = 1;
currentGame.powerups++;
break;
case P_SUPER:
weapon[1].ammo[0] = 5;
weapon[1].damage = 5;
weapon[1].reload[0] = 7;
if (weapon[1].flags & WF_STRAIGHT)
weapon[1].flags -= WF_STRAIGHT;
if (weapon[1].flags & WF_THIN_SPREAD)
weapon[1].flags -= WF_THIN_SPREAD;
if (!(weapon[1].flags & WF_WIDE_SPREAD))
weapon[1].flags += WF_WIDE_SPREAD;
sprintf(temp, "Picked up a Super Charge!!");
if (player.ammo[0] < 50)
player.ammo[0] = 50;
player.weaponType[0] = 1;
currentGame.powerups++;
break;
case P_PLASMA_AMMO:
Math::limitCharAdd(&player.ammo[0], collectable->value, 0, currentGame.maxPlasmaAmmo);
if (player.ammo[0] == currentGame.maxPlasmaAmmo)
sprintf(temp, "Plasma cells at Maximum");
else
{
if (collectable->value > 1)
{
sprintf(temp, "Got %d plasma cells", collectable->value);
}
else
{
sprintf(temp, "Got a plasma cell");
if ((rand() % 25) == 0)
sprintf(temp, "Got one whole plasma cell (wahoo!)");
}
}
player.weaponType[0] = 1;
currentGame.cellPickups += collectable->value;
break;
case P_CARGO:
strcpy(temp, "Picked up some Cargo");
currentGame.cargoPickups++;
break;
case P_SLAVES:
sprintf(temp, "Rescued %d slaves", collectable->value);
currentGame.slavesRescued += collectable->value;
break;
case P_ESCAPEPOD:
sprintf(temp, "Picked up an Escape Pod");
break;
case P_ORE:
sprintf(temp, "Picked up some Ore");
break;
}
updateMissionRequirements(M_COLLECT, collectable->type, collectable->value);
collectable->active = 0;
if (collectable->type != P_MINE)
{
setInfoLine(temp, FONT_WHITE);
if (collectable->type == P_SHIELD)
playSound(SFX_SHIELDUP);
else
playSound(SFX_PICKUP);
}
}
// stop people from exploiting a weapon check condition
if (player.ammo[0] == 0)
{
player.weaponType[0] = 0;
weapon[1] = weapon[0]; // reset to weapon 1 defaults
}
}
if (collectable->life < 1)
{
collectable->active = 0;
if ((collectable->type == P_CARGO) || (collectable->type == P_ESCAPEPOD) || (collectable->type == P_SLAVES))
updateMissionRequirements(M_PROTECT_PICKUP, collectable->type, 1);
}
if (collectable->active == 1)
{
prevCollectable = collectable;
engine.collectableTail = collectable;
}
else
{
if (collectable->type == P_MINE)
explodeMine(collectable);
prevCollectable->next = collectable->next;
delete collectable;
collectable = prevCollectable;
}
}
}