2011-08-24 14:14:44 +02:00
|
|
|
/*
|
|
|
|
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
|
2015-02-26 17:20:36 +01:00
|
|
|
as published by the Free Software Foundation; either version 3
|
2011-08-24 14:14:44 +02:00
|
|
|
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
|
2015-02-26 17:20:36 +01:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
2015-02-26 17:20:36 +01:00
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2011-08-24 14:14:44 +02:00
|
|
|
*/
|
|
|
|
|
2011-08-26 21:29:04 +02:00
|
|
|
#include "Starfighter.h"
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-28 04:03:06 +01:00
|
|
|
// Deny the Super Charge in Nightmare difficulty.
|
|
|
|
if (type == P_SUPER)
|
|
|
|
{
|
|
|
|
if (currentGame.difficulty >= DIFFICULTY_NIGHTMARE)
|
|
|
|
{
|
|
|
|
type = P_PLASMA_DAMAGE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-28 04:16:53 +01:00
|
|
|
// Shield bonus is useless in Nightmare difficulty; give cash instead.
|
|
|
|
if (type == P_SHIELD)
|
|
|
|
{
|
|
|
|
if (currentGame.difficulty >= DIFFICULTY_NIGHTMARE)
|
|
|
|
{
|
|
|
|
type = P_CASH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-24 14:14:44 +02:00
|
|
|
collectables *collectable = new collectables;
|
|
|
|
|
|
|
|
collectable->next = NULL;
|
2011-08-26 16:14:58 +02:00
|
|
|
collectable->active = true;
|
2011-08-24 14:14:44 +02:00
|
|
|
collectable->x = x;
|
|
|
|
collectable->y = y;
|
|
|
|
|
2011-08-26 23:27:16 +02:00
|
|
|
collectable->dx = rrand(-100, 100);
|
2011-08-24 14:14:44 +02:00
|
|
|
if (collectable->dx != 0)
|
|
|
|
collectable->dx /= 100;
|
|
|
|
|
2011-08-26 23:27:16 +02:00
|
|
|
collectable->dy = rrand(-100, 100);
|
2011-08-24 14:14:44 +02:00
|
|
|
if (collectable->dy != 0)
|
|
|
|
collectable->dy /= 100;
|
|
|
|
|
|
|
|
collectable->type = type;
|
|
|
|
collectable->value = value;
|
|
|
|
collectable->life = life;
|
|
|
|
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case P_CASH:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[24];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_ROCKET:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[49];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_PLASMA_AMMO:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[25];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_SHIELD:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[26];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_PLASMA_SHOT:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[27];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_PLASMA_RATE:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[28];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_PLASMA_DAMAGE:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[29];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_CARGO:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[32];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_SUPER:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[50];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_MINE:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[31];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_SLAVES:
|
|
|
|
case P_ESCAPEPOD:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[45];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case P_ORE:
|
2011-08-26 23:53:46 +02:00
|
|
|
collectable->image = shape[46 + rand() % 3];
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
engine.collectableTail->next = collectable;
|
|
|
|
engine.collectableTail = collectable;
|
|
|
|
}
|
|
|
|
|
2011-08-26 21:29:04 +02:00
|
|
|
static void explodeMine(collectables *collectable)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
if ((collectable->x >= 0) && (collectable->x <= 800) && (collectable->y >= 0) && (collectable->y <= 600))
|
2012-03-02 23:00:35 +01:00
|
|
|
playSound(SFX_EXPLOSION, collectable->x);
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
for (int i = 0 ; i < 10 ; i++)
|
|
|
|
addExplosion(collectable->x + rand() % 25 - rand() % 25, collectable->y + rand() % 25 - rand() % 25, E_BIG_EXPLOSION);
|
|
|
|
|
2011-08-24 22:22:26 +02:00
|
|
|
if (checkPlayerShockDamage(collectable->x, collectable->y))
|
2011-08-24 14:14:44 +02:00
|
|
|
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)
|
|
|
|
{
|
2011-08-26 23:27:16 +02:00
|
|
|
if (collision(collectable, bullet))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2011-08-26 16:14:58 +02:00
|
|
|
collectable->active = false;
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
if (bullet->id != WT_CHARGER)
|
|
|
|
{
|
2011-08-26 16:14:58 +02:00
|
|
|
bullet->active = false;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bullet->shield--;
|
|
|
|
if (bullet->shield < 0)
|
2011-08-26 16:14:58 +02:00
|
|
|
bullet->active = false;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (bullet->owner == &player)
|
|
|
|
{
|
|
|
|
currentGame.minesKilled++;
|
|
|
|
currentGame.hits++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-26 16:14:58 +02:00
|
|
|
if (collectable->active)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2011-08-26 16:14:58 +02:00
|
|
|
if (collectable->active)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
if ((collectable->x + collectable->image->w > 0) && (collectable->x < 800) && (collectable->y + collectable->image->h > 0) && (collectable->y < 600))
|
2011-08-26 23:53:46 +02:00
|
|
|
blit(collectable->image, (int)collectable->x, (int)collectable->y);
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-02-27 05:23:08 +01:00
|
|
|
collectable->x += engine.ssx + engine.smx;
|
2015-02-27 05:31:26 +01:00
|
|
|
collectable->y += engine.ssy + engine.smy;
|
2011-08-24 14:14:44 +02:00
|
|
|
collectable->x += collectable->dx;
|
|
|
|
collectable->y += collectable->dy;
|
|
|
|
|
|
|
|
collectable->life--;
|
|
|
|
|
2011-08-26 23:27:16 +02:00
|
|
|
if ((player.shield > 0) && (collision(collectable, &player)))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
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:
|
2015-02-28 14:47:26 +01:00
|
|
|
limitCharAdd(&player.ammo[1], collectable->value, 0,
|
|
|
|
currentGame.maxRocketAmmo);
|
2011-08-24 14:14:44 +02:00
|
|
|
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:
|
2011-08-26 23:27:16 +02:00
|
|
|
limitInt(&(player.shield += 10), 0, player.maxShield);
|
2011-08-24 14:14:44 +02:00
|
|
|
currentGame.shieldPickups ++;
|
|
|
|
sprintf(temp, "Restored 10 shield points");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case P_PLASMA_RATE:
|
|
|
|
if (player.ammo[0] < 50)
|
|
|
|
player.ammo[0] = 50;
|
2015-02-28 14:15:53 +01:00
|
|
|
if (weapon[W_PLAYER_WEAPON].reload[0] <= rate2reload[currentGame.maxPlasmaRate])
|
2011-09-11 21:57:57 +02:00
|
|
|
sprintf(temp, "Firing Rate already at Maximum");
|
2011-08-24 14:14:44 +02:00
|
|
|
else
|
2011-09-11 21:57:57 +02:00
|
|
|
{
|
2015-02-28 14:15:53 +01:00
|
|
|
weapon[W_PLAYER_WEAPON].reload[0] -= 2;
|
2011-08-24 14:14:44 +02:00
|
|
|
sprintf(temp, "Firing rate increased");
|
2011-09-11 21:57:57 +02:00
|
|
|
}
|
2011-08-24 14:14:44 +02:00
|
|
|
currentGame.powerups++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case P_PLASMA_SHOT:
|
|
|
|
if (player.ammo[0] < 50)
|
|
|
|
player.ammo[0] = 50;
|
2015-02-28 14:15:53 +01:00
|
|
|
if (weapon[W_PLAYER_WEAPON].ammo[0] >= currentGame.maxPlasmaOutput)
|
2011-09-11 21:57:57 +02:00
|
|
|
sprintf(temp, "Plasma output already at Maximum");
|
2011-08-24 14:14:44 +02:00
|
|
|
else
|
2011-09-11 21:57:57 +02:00
|
|
|
{
|
2015-02-28 14:15:53 +01:00
|
|
|
weapon[W_PLAYER_WEAPON].ammo[0]++;
|
2011-08-24 14:14:44 +02:00
|
|
|
sprintf(temp, "Plasma output increased");
|
2011-09-11 21:57:57 +02:00
|
|
|
}
|
2011-08-24 14:14:44 +02:00
|
|
|
currentGame.powerups++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case P_PLASMA_DAMAGE:
|
|
|
|
if (player.ammo[0] < 50)
|
|
|
|
player.ammo[0] = 50;
|
2015-02-28 14:15:53 +01:00
|
|
|
if (weapon[W_PLAYER_WEAPON].damage >= currentGame.maxPlasmaDamage)
|
2011-09-11 21:57:57 +02:00
|
|
|
sprintf(temp, "Plasma damage already at Maximum");
|
|
|
|
else {
|
2015-02-28 14:15:53 +01:00
|
|
|
weapon[W_PLAYER_WEAPON].damage++;
|
2011-08-24 14:14:44 +02:00
|
|
|
sprintf(temp, "Plasma damage increased");
|
2011-09-11 21:57:57 +02:00
|
|
|
}
|
2011-08-24 14:14:44 +02:00
|
|
|
currentGame.powerups++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case P_SUPER:
|
2015-02-28 14:15:53 +01:00
|
|
|
weapon[W_PLAYER_WEAPON].ammo[0] = 5;
|
|
|
|
weapon[W_PLAYER_WEAPON].damage = 5;
|
|
|
|
weapon[W_PLAYER_WEAPON].reload[0] = rate2reload[5];
|
|
|
|
weapon[W_PLAYER_WEAPON].flags |= WF_SPREAD;
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
sprintf(temp, "Picked up a Super Charge!!");
|
|
|
|
|
|
|
|
if (player.ammo[0] < 50)
|
|
|
|
player.ammo[0] = 50;
|
|
|
|
currentGame.powerups++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case P_PLASMA_AMMO:
|
2011-09-11 21:57:57 +02:00
|
|
|
if (player.ammo[0] >= currentGame.maxPlasmaAmmo)
|
|
|
|
sprintf(temp, "Plasma cells already at Maximum");
|
2011-08-24 14:14:44 +02:00
|
|
|
else
|
|
|
|
{
|
2011-09-11 21:57:57 +02:00
|
|
|
limitCharAdd(&player.ammo[0], collectable->value, 0, currentGame.maxPlasmaAmmo);
|
2011-08-24 14:14:44 +02:00
|
|
|
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!)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
|
2011-08-26 16:14:58 +02:00
|
|
|
collectable->active = false;
|
2011-08-24 14:14:44 +02:00
|
|
|
if (collectable->type != P_MINE)
|
|
|
|
{
|
|
|
|
setInfoLine(temp, FONT_WHITE);
|
|
|
|
if (collectable->type == P_SHIELD)
|
2012-03-02 23:00:35 +01:00
|
|
|
playSound(SFX_SHIELDUP, player.x);
|
2011-08-24 14:14:44 +02:00
|
|
|
else
|
2012-03-02 23:00:35 +01:00
|
|
|
playSound(SFX_PICKUP, player.x);
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// stop people from exploiting a weapon check condition
|
|
|
|
if (player.ammo[0] == 0)
|
|
|
|
{
|
2015-02-28 14:15:53 +01:00
|
|
|
weapon[W_PLAYER_WEAPON].ammo[0] = currentGame.minPlasmaOutput;
|
|
|
|
weapon[W_PLAYER_WEAPON].damage = currentGame.minPlasmaDamage;
|
|
|
|
weapon[W_PLAYER_WEAPON].reload[0] = rate2reload[currentGame.minPlasmaRate];
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (collectable->life < 1)
|
|
|
|
{
|
2011-08-26 16:14:58 +02:00
|
|
|
collectable->active = false;
|
2011-08-24 14:14:44 +02:00
|
|
|
if ((collectable->type == P_CARGO) || (collectable->type == P_ESCAPEPOD) || (collectable->type == P_SLAVES))
|
|
|
|
updateMissionRequirements(M_PROTECT_PICKUP, collectable->type, 1);
|
|
|
|
}
|
|
|
|
|
2011-08-26 16:14:58 +02:00
|
|
|
if (collectable->active)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
prevCollectable = collectable;
|
|
|
|
engine.collectableTail = collectable;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (collectable->type == P_MINE)
|
|
|
|
explodeMine(collectable);
|
|
|
|
prevCollectable->next = collectable->next;
|
|
|
|
delete collectable;
|
|
|
|
collectable = prevCollectable;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|