2011-08-24 14:14:44 +02:00
|
|
|
/*
|
|
|
|
Copyright (C) 2003 Parallel Realities
|
2015-03-01 21:37:32 +01:00
|
|
|
Copyright (C) 2011, 2012 Guus Sliepen
|
|
|
|
Copyright (C) 2012, 2015 Julian Marchant
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
2011-08-26 21:29:04 +02:00
|
|
|
object defEnemy[MAX_DEFALIENS];
|
|
|
|
object enemy[MAX_ALIENS];
|
|
|
|
|
2015-03-05 03:30:23 +01:00
|
|
|
/*
|
|
|
|
This simply pulls back an alien from the array that is
|
|
|
|
"dead" (no shield) and returns the index number so we can have
|
|
|
|
a new one.
|
|
|
|
*/
|
|
|
|
static int alien_getFreeIndex()
|
|
|
|
{
|
|
|
|
for (int i = 0 ; i < engine.maxAliens ; i++)
|
|
|
|
{
|
|
|
|
if (!enemy[i].active)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool alien_add()
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-05 03:30:23 +01:00
|
|
|
int index = alien_getFreeIndex();
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
if ((index == -1) || (currentGame.area == 23) || (currentGame.area == 26))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
signed char *alienArray;
|
|
|
|
signed char numberOfAliens = 1;
|
|
|
|
|
2015-03-05 03:30:23 +01:00
|
|
|
alienArray = new signed char[8];
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
switch(currentGame.area)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case 3:
|
|
|
|
case 11:
|
|
|
|
numberOfAliens = 1;
|
|
|
|
alienArray[0] = CD_DUALFIGHTER;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
numberOfAliens = 2;
|
|
|
|
alienArray[0] = CD_DUALFIGHTER;
|
|
|
|
alienArray[1] = CD_PROTOFIGHTER;
|
|
|
|
break;
|
2015-02-28 16:32:20 +01:00
|
|
|
case 7:
|
|
|
|
case 8:
|
|
|
|
numberOfAliens = 3;
|
|
|
|
alienArray[0] = CD_DUALFIGHTER;
|
|
|
|
alienArray[1] = CD_PROTOFIGHTER;
|
|
|
|
alienArray[2] = CD_AIMFIGHTER;
|
|
|
|
break;
|
2011-08-24 14:14:44 +02:00
|
|
|
case 9:
|
2015-02-28 16:32:20 +01:00
|
|
|
// This is the mission where you need to disable cargo ships.
|
|
|
|
// Missiles are extremely bad in this mission, not because
|
|
|
|
// of the damage they do to you, but because they tend to
|
|
|
|
// accidentally destroy the cargo ships. Therefore, ships
|
|
|
|
// with missiles (dual fighters and missile boats) are
|
|
|
|
// excluded from this mission.
|
|
|
|
numberOfAliens = 2;
|
|
|
|
alienArray[0] = CD_PROTOFIGHTER;
|
|
|
|
alienArray[1] = CD_AIMFIGHTER;
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
case 15:
|
|
|
|
numberOfAliens = 1;
|
|
|
|
alienArray[0] = CD_ASTEROID;
|
|
|
|
break;
|
2011-08-24 14:14:44 +02:00
|
|
|
case 13:
|
|
|
|
case 14:
|
|
|
|
case 16:
|
|
|
|
numberOfAliens = 4;
|
|
|
|
alienArray[0] = CD_DUALFIGHTER;
|
|
|
|
alienArray[1] = CD_PROTOFIGHTER;
|
|
|
|
alienArray[2] = CD_MISSILEBOAT;
|
|
|
|
alienArray[3] = CD_AIMFIGHTER;
|
|
|
|
break;
|
2015-02-28 16:32:20 +01:00
|
|
|
case 18:
|
|
|
|
numberOfAliens = 2;
|
|
|
|
alienArray[0] = CD_DUALFIGHTER;
|
|
|
|
alienArray[1] = CD_MINER;
|
|
|
|
break;
|
2011-08-24 14:14:44 +02:00
|
|
|
case 25:
|
|
|
|
numberOfAliens = 6;
|
|
|
|
alienArray[0] = CD_DUALFIGHTER;
|
|
|
|
alienArray[1] = CD_PROTOFIGHTER;
|
|
|
|
alienArray[2] = CD_MISSILEBOAT;
|
|
|
|
alienArray[3] = CD_AIMFIGHTER;
|
|
|
|
alienArray[4] = CD_ESCORT;
|
|
|
|
alienArray[5] = CD_MOBILE_RAY;
|
|
|
|
break;
|
|
|
|
case 22:
|
|
|
|
numberOfAliens = 2;
|
|
|
|
alienArray[0] = CD_AIMFIGHTER;
|
|
|
|
alienArray[1] = CD_DUALFIGHTER;
|
|
|
|
break;
|
|
|
|
case 24:
|
|
|
|
numberOfAliens = 2;
|
|
|
|
alienArray[0] = CD_ASTEROID;
|
|
|
|
alienArray[1] = CD_ASTEROID2;
|
|
|
|
break;
|
|
|
|
case MAX_MISSIONS - 1:
|
|
|
|
numberOfAliens = 3;
|
|
|
|
alienArray[0] = CD_DUALFIGHTER;
|
|
|
|
alienArray[1] = CD_MISSILEBOAT;
|
|
|
|
alienArray[2] = CD_AIMFIGHTER;
|
|
|
|
if (currentGame.system == 2)
|
|
|
|
{
|
|
|
|
numberOfAliens = 4;
|
|
|
|
alienArray[3] = CD_PROTOFIGHTER;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
numberOfAliens = 1;
|
|
|
|
alienArray[0] = CD_DUALFIGHTER;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
signed char randEnemy = alienArray[rand() % numberOfAliens];
|
|
|
|
|
2015-02-28 14:15:53 +01:00
|
|
|
if ((currentGame.area != 10) && (currentGame.area != 15) &&
|
|
|
|
(currentGame.area != 24))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
if ((currentGame.system == 1) && (currentGame.area == MAX_MISSIONS - 1))
|
|
|
|
{
|
|
|
|
if ((rand() % 5) == 0)
|
|
|
|
randEnemy = CD_SLAVETRANSPORT;
|
|
|
|
}
|
|
|
|
|
2015-02-28 21:22:27 +01:00
|
|
|
if ((currentGame.area != MAX_MISSIONS - 1) &&
|
|
|
|
((currentGame.maxPlasmaRate > currentGame.minPlasmaRate) ||
|
|
|
|
(currentGame.maxPlasmaOutput > currentGame.minPlasmaOutput) ||
|
|
|
|
(currentGame.maxPlasmaDamage > currentGame.minPlasmaDamage)))
|
2015-02-28 15:45:26 +01:00
|
|
|
{
|
|
|
|
if ((rand() % 6) == 0)
|
|
|
|
randEnemy = CD_TRANSPORTSHIP;
|
|
|
|
}
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
2011-08-24 14:46:34 +02:00
|
|
|
delete[] alienArray;
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
enemy[index] = defEnemy[randEnemy];
|
2011-08-26 16:14:58 +02:00
|
|
|
enemy[index].active = true;
|
2011-08-24 14:14:44 +02:00
|
|
|
enemy[index].face = rand() % 2;
|
|
|
|
enemy[index].owner = &enemy[index]; // Most enemies will own themselves
|
|
|
|
enemy[index].target = &enemy[index];
|
|
|
|
enemy[index].thinktime = (50 + rand() % 50);
|
|
|
|
enemy[index].systemPower = enemy[index].maxShield;
|
|
|
|
enemy[index].deathCounter = 0 - (enemy[index].maxShield * 3);
|
|
|
|
enemy[index].hit = 0;
|
|
|
|
|
2011-08-26 23:27:16 +02:00
|
|
|
limitInt(&enemy[index].deathCounter, -250, 0);
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
// Attempts to place an alien. If it fails, the alien is deactivated.
|
|
|
|
for (int i = 0 ; i < 100 ; i++)
|
|
|
|
{
|
2015-03-05 03:30:23 +01:00
|
|
|
if (alien_place(&enemy[index]))
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
2011-08-26 16:14:58 +02:00
|
|
|
enemy[index].active = false;
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2011-08-26 16:55:46 +02:00
|
|
|
return false;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (enemy[index].classDef == CD_CARGOSHIP)
|
|
|
|
addCargo(&enemy[index], P_CARGO);
|
|
|
|
|
|
|
|
if (enemy[index].classDef == CD_MOBILE_RAY)
|
|
|
|
enemy[index].shield = 25;
|
|
|
|
|
|
|
|
if (enemy[index].classDef == CD_ESCORT)
|
|
|
|
enemy[index].shield = 50;
|
|
|
|
|
2011-08-26 23:27:16 +02:00
|
|
|
enemy[index].dx = rrand(-2, 2);
|
|
|
|
enemy[index].dy = rrand(-2, 2);
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
enemy[index].ammo[0] = 0;
|
|
|
|
|
|
|
|
if (currentGame.area == 18)
|
2011-09-04 14:23:31 +02:00
|
|
|
enemy[index].flags |= FL_HASMINIMUMSPEED;
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2011-08-26 16:55:46 +02:00
|
|
|
return true;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
void alien_addDrone(object *hostAlien)
|
2015-03-05 03:30:23 +01:00
|
|
|
{
|
|
|
|
int index = alien_getFreeIndex();
|
|
|
|
|
|
|
|
if (index == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
enemy[index] = defEnemy[CD_DRONE];
|
|
|
|
enemy[index].active = true;
|
|
|
|
enemy[index].face = rand() % 2;
|
|
|
|
enemy[index].owner = &enemy[index]; // Most enemies will own themselves
|
|
|
|
enemy[index].target = &enemy[index];
|
|
|
|
enemy[index].thinktime = (50 + rand() % 50);
|
|
|
|
enemy[index].systemPower = enemy[index].maxShield;
|
|
|
|
enemy[index].deathCounter = 0 - (enemy[index].maxShield * 3);
|
|
|
|
enemy[index].hit = 0;
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
enemy[index].x = hostAlien->x + rand() % 50;
|
|
|
|
enemy[index].y = hostAlien->y + rand() % 50;
|
2015-03-05 03:30:23 +01:00
|
|
|
}
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
void alien_addSmallAsteroid(object *hostAlien)
|
2015-03-05 03:30:23 +01:00
|
|
|
{
|
|
|
|
if (engine.missionCompleteTimer != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int index = -1;
|
|
|
|
int debris = 1 + rand() % 10;
|
|
|
|
|
|
|
|
for (int i = 0 ; i < debris ; i++)
|
2015-03-07 05:18:31 +01:00
|
|
|
addBullet(&weapon[W_ROCKETS], hostAlien, 0, 0);
|
2015-03-05 03:30:23 +01:00
|
|
|
|
|
|
|
for (int i = 10 ; i < 20 ; i++)
|
|
|
|
if (!enemy[i].active)
|
|
|
|
index = i;
|
|
|
|
|
|
|
|
if (index == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((rand() % 10) > 3)
|
|
|
|
{
|
|
|
|
enemy[index] = defEnemy[CD_ASTEROID2];
|
|
|
|
enemy[index].imageIndex[0] = enemy[index].imageIndex[1] = 39 + rand() % 2;
|
|
|
|
enemy[index].image[0] = shipShape[enemy[index].imageIndex[0]];
|
|
|
|
enemy[index].image[1] = shipShape[enemy[index].imageIndex[1]];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
enemy[index] = defEnemy[CD_DRONE];
|
|
|
|
}
|
|
|
|
|
|
|
|
enemy[index].owner = &enemy[index]; // Most enemies will own themselves
|
|
|
|
enemy[index].target = &enemy[index];
|
|
|
|
enemy[index].thinktime = 1;
|
|
|
|
enemy[index].systemPower = enemy[index].maxShield;
|
|
|
|
enemy[index].deathCounter = 0 - (enemy[index].maxShield * 3);
|
|
|
|
enemy[index].hit = 0;
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
enemy[index].x = hostAlien->x;
|
|
|
|
enemy[index].y = hostAlien->y;
|
2015-03-05 03:30:23 +01:00
|
|
|
enemy[index].active = true;
|
|
|
|
}
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
void alien_addFriendly(int type)
|
2015-03-05 03:30:23 +01:00
|
|
|
{
|
|
|
|
if (type != FR_SID)
|
|
|
|
enemy[type] = defEnemy[CD_FRIEND];
|
|
|
|
else
|
|
|
|
enemy[type] = defEnemy[CD_SID];
|
|
|
|
|
|
|
|
enemy[type].owner = &enemy[type];
|
|
|
|
enemy[type].target = &enemy[type];
|
|
|
|
enemy[type].active = true;
|
|
|
|
|
|
|
|
if (rand() % 2 == 0)
|
|
|
|
enemy[type].x = rrand((int)(screen->w / 2), (int)(screen->w / 2) + 150);
|
|
|
|
else
|
|
|
|
enemy[type].x = rrand((int)(screen->w / 2) - 150, (int)(screen->w / 2));
|
|
|
|
|
|
|
|
if (rand() % 2 == 0)
|
|
|
|
enemy[type].y = rrand((int)(screen->h / 2), (int)(screen->h / 2) + 150);
|
|
|
|
else
|
|
|
|
enemy[type].y = rrand((int)(screen->h / 2) - 150, (int)(screen->h / 2));
|
|
|
|
|
|
|
|
if (type == FR_PHOEBE)
|
|
|
|
enemy[type].classDef = CD_PHOEBE;
|
|
|
|
|
|
|
|
if (type == FR_URSULA)
|
|
|
|
enemy[type].classDef = CD_URSULA;
|
|
|
|
|
|
|
|
// For the sake of it being the final battle :)
|
|
|
|
if (currentGame.area == 25)
|
|
|
|
enemy[type].flags |= FL_IMMORTAL;
|
|
|
|
}
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
bool alien_place(object *alien)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
if (rand() % 2 == 0)
|
|
|
|
alien->x = rrand(screen->w, screen->w * 2);
|
|
|
|
else
|
|
|
|
alien->x = rrand(-screen->w, 0);
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
if (rand() % 2 == 0)
|
|
|
|
alien->y = rrand(screen->h, screen->h * 2);
|
|
|
|
else
|
|
|
|
alien->y = rrand(-screen->h, 0);
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
if (currentGame.area == 24)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
alien->x = screen->w;
|
|
|
|
alien->y = rrand(screen->h / 3, (2 * screen->h) / 3);
|
|
|
|
}
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
for (int i = 0 ; i < MAX_ALIENS ; i++)
|
|
|
|
{
|
|
|
|
if ((enemy[i].owner != alien) && (enemy[i].shield > 0))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
if (collision(alien->x, alien->y, alien->image[0]->w, alien->image[0]->h, enemy[i].x, enemy[i].y, enemy[i].image[0]->w, enemy[i].image[0]->h))
|
|
|
|
return false;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
2015-03-07 05:18:31 +01:00
|
|
|
}
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
return true;
|
|
|
|
}
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
void alien_setAI(object *alien)
|
|
|
|
{
|
|
|
|
// Make friendly craft generally concentrate on smaller fighters
|
|
|
|
if ((alien->flags & FL_FRIEND) && (alien->target == &enemy[WC_BOSS]))
|
|
|
|
{
|
|
|
|
if ((rand() % 5) == 0)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
alien->target = alien;
|
|
|
|
alien->thinktime = 0;
|
|
|
|
return;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
2015-03-07 05:18:31 +01:00
|
|
|
}
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
int i = rand() % 10;
|
|
|
|
float tx = alien->target->x;
|
|
|
|
float ty = alien->target->y;
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
int chase = 0; // Chance in 10 of chasing player
|
|
|
|
int area = 0; // Chance in 10 of moving to an area around the player
|
|
|
|
int stop = 0; // Chance in 10 of hanging back
|
|
|
|
int point = 0; // Size of area alien will move into
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
switch (alien->AIType)
|
|
|
|
{
|
|
|
|
case AI_NORMAL:
|
|
|
|
chase = 3;
|
|
|
|
point = 6;
|
|
|
|
stop = 9;
|
|
|
|
area = 250;
|
|
|
|
break;
|
|
|
|
case AI_OFFENSIVE:
|
|
|
|
chase = 7;
|
|
|
|
point = 8;
|
|
|
|
stop = 9;
|
|
|
|
area = 50;
|
|
|
|
break;
|
|
|
|
case AI_DEFENSIVE:
|
|
|
|
chase = 2;
|
|
|
|
point = 6;
|
|
|
|
stop = 8;
|
|
|
|
area = 300;
|
|
|
|
break;
|
|
|
|
case AI_EVASIVE:
|
|
|
|
chase = 1;
|
|
|
|
point = 8;
|
|
|
|
stop = 9;
|
|
|
|
area = 600;
|
|
|
|
break;
|
|
|
|
case AI_WANDER:
|
|
|
|
chase = -1;
|
|
|
|
point = 0;
|
|
|
|
stop = 10;
|
|
|
|
area = 1200;
|
|
|
|
break;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
if (i <= chase)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
// Chase the target
|
|
|
|
alien->dx = ((alien->x - tx) / ((300 / alien->speed) + rand() % 100));
|
|
|
|
alien->dy = ((alien->y - ty) / ((300 / alien->speed) + rand() % 100));
|
|
|
|
return;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
2015-03-07 05:18:31 +01:00
|
|
|
else if ((i >= point) && (i <= stop))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
// Fly to a random point around the target
|
|
|
|
tx += (rand() % area - (rand() % area * 2));
|
|
|
|
ty += (rand() % area - (rand() % area * 2));
|
|
|
|
alien->dx = ((alien->x - tx) / ((300 / alien->speed) + rand() % 100));
|
|
|
|
alien->dy = ((alien->y - ty) / ((300 / alien->speed) + rand() % 100));
|
|
|
|
return;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
2015-03-07 05:18:31 +01:00
|
|
|
else
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
// Hang back
|
|
|
|
alien->dx = 0;
|
|
|
|
alien->dy = 0;
|
|
|
|
return;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
void alien_setKlineAttackMethod(object *alien)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
alien->maxShield -= 500;
|
|
|
|
if (alien->maxShield == 0)
|
|
|
|
alien->flags &= ~FL_CANNOTDIE;
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
if (alien->maxShield == 1000)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
setRadioMessage(FACE_KLINE, "Very good, Bainfield. Now let's get a little more serious...", 1);
|
|
|
|
alien->weaponType[0] = W_SPREADSHOT;
|
|
|
|
alien->chance[1] = 40;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
2015-03-07 05:18:31 +01:00
|
|
|
else if (alien->maxShield == 500)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
setRadioMessage(FACE_KLINE, "Your ability to stay alive irritates me!! Try dodging some of these!!", 1);
|
|
|
|
alien->weaponType[0] = W_DIRSHOCKMISSILE;
|
|
|
|
alien->weaponType[1] = W_DIRSHOCKMISSILE;
|
|
|
|
alien->chance[0] = 2;
|
|
|
|
alien->chance[1] = 2;
|
|
|
|
alien->flags |= FL_AIMS;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
2015-03-07 05:18:31 +01:00
|
|
|
else if (alien->maxShield == 0)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
setRadioMessage(FACE_KLINE, "ENOUGH!! THIS ENDS NOW!!!", 1);
|
|
|
|
alien->weaponType[0] = W_AIMED_SHOT;
|
|
|
|
alien->weaponType[1] = W_MICRO_HOMING_MISSILES;
|
|
|
|
alien->flags |= FL_CANCLOAK;
|
|
|
|
alien->chance[0] = 100;
|
|
|
|
alien->chance[1] = 2;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
alien->shield = 500;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
This AI is exclusively for Kline.
|
|
|
|
*/
|
|
|
|
void alien_setKlineAI(object *alien)
|
|
|
|
{
|
|
|
|
// Weapon type change
|
|
|
|
if ((rand() % 3) == 0)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
if (currentGame.area != 26)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
alien->flags &= ~FL_AIMS;
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
switch(rand() % 2)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
case 0:
|
|
|
|
alien->weaponType[0] = W_TRIPLE_SHOT;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
alien->weaponType[0] = W_AIMED_SHOT;
|
|
|
|
alien->flags |= FL_AIMS;
|
|
|
|
break;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
alien->flags &= ~(FL_CIRCLES | FL_CONTINUOUS_FIRE | FL_DROPMINES);
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
switch(rand() % 10)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-07 05:18:31 +01:00
|
|
|
case 0:
|
|
|
|
if ((alien->weaponType[0] != W_DIRSHOCKMISSILE) && (alien->weaponType[1] != W_MICRO_HOMING_MISSILES))
|
|
|
|
alien->flags |= FL_CONTINUOUS_FIRE;
|
|
|
|
alien->dx = ((alien->x - alien->target->x) / ((300 / alien->speed) + rand() % 100));
|
|
|
|
alien->dy = ((alien->y - alien->target->y) / ((300 / alien->speed) + rand() % 100));
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
2015-03-07 05:18:31 +01:00
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
// Kline only attacks then he is ready!
|
|
|
|
if ((!(alien->flags & FL_NOFIRE)) && (currentGame.area == 11))
|
|
|
|
alien->flags |= FL_DROPMINES;
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
2015-03-07 05:18:31 +01:00
|
|
|
case 3:
|
|
|
|
case 4:
|
|
|
|
alien->flags |= FL_CIRCLES;
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
default:
|
2015-03-07 05:18:31 +01:00
|
|
|
alien_setAI(alien);
|
2011-08-24 14:14:44 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
"Looks" for an enemy by picking a randomly active enemy and using them
|
|
|
|
as a target. If the target is too far away, it will be ignored.
|
|
|
|
*/
|
2015-03-07 05:18:31 +01:00
|
|
|
void alien_searchForTarget(object *alien)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if (alien->flags & FL_WEAPCO)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
i = (rand() % 10);
|
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
alien->target = &player;
|
2011-08-24 14:14:44 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
i = rand() % MAX_ALIENS;
|
|
|
|
|
|
|
|
object *targetEnemy = &enemy[i];
|
|
|
|
|
|
|
|
// Tell Sid not to attack craft that are already disabled or can
|
|
|
|
// return fire. This will save him from messing about (unless we're on the last mission)
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->classDef == CD_SID) && (currentGame.area != 25))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
if ((targetEnemy->flags & FL_DISABLED) || (!(targetEnemy->flags & FL_NOFIRE)))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tell Phoebe and Ursula not to attack ships that cannot fire or are disabled (unless we're on the last mission)
|
|
|
|
if (currentGame.area != 25)
|
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->classDef == CD_PHOEBE) || (alien->classDef == CD_URSULA))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
// Don't attack the boss or we could be here all day(!)
|
|
|
|
if (targetEnemy->classDef == CD_BOSS)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((targetEnemy->flags & FL_DISABLED) || (targetEnemy->flags & FL_NOFIRE))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((targetEnemy->shield < 1) || (!targetEnemy->active))
|
|
|
|
return;
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((targetEnemy->flags & FL_WEAPCO) && (alien->flags & FL_WEAPCO))
|
2011-08-24 14:14:44 +02:00
|
|
|
return;
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((targetEnemy->flags & FL_FRIEND) && (alien->flags & FL_FRIEND))
|
2011-08-24 14:14:44 +02:00
|
|
|
return;
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if (abs((int)alien->x - (int)alien->target->x) > 550)
|
2011-08-24 14:14:44 +02:00
|
|
|
return;
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if (abs((int)alien->y - (int)alien->target->y) > 400)
|
2011-08-24 14:14:44 +02:00
|
|
|
return;
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
alien->target = targetEnemy;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
/*
|
|
|
|
Do various checks to see if the alien can fire at the target.
|
|
|
|
*/
|
|
|
|
int alien_checkTarget(object *alien)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
// No target
|
2015-03-06 15:37:21 +01:00
|
|
|
if (alien->target == alien)
|
2011-08-24 14:14:44 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Whilst firing a Ray, no other weapons can be fired!
|
2015-03-06 15:37:21 +01:00
|
|
|
if (alien->flags & FL_FIRERAY)
|
2011-08-24 14:14:44 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// The target is on the same side as you!
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->flags & FL_WEAPCO) && (alien->target->flags & FL_WEAPCO))
|
2011-08-24 14:14:44 +02:00
|
|
|
return 0;
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->flags & FL_FRIEND) && (alien->target->flags & FL_FRIEND))
|
2011-08-24 14:14:44 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// You're facing the wrong way
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->face == 0) && (alien->target->x < alien->x))
|
2011-08-24 14:14:44 +02:00
|
|
|
return 0;
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->face == 1) && (alien->target->x > alien->x))
|
2011-08-24 14:14:44 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Slightly more than half a screen away from you
|
2015-03-06 15:37:21 +01:00
|
|
|
if (abs((int)alien->x - (int)alien->target->x) > 550)
|
2011-08-24 14:14:44 +02:00
|
|
|
return 0;
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->flags & FL_AIMS) || (alien->flags & FL_CONTINUOUS_FIRE))
|
2011-08-24 14:14:44 +02:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
// Not at the correct vertical height
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->y < alien->target->y - 15) || (alien->y > alien->target->y + alien->target->image[0]->h + 15))
|
2011-08-24 14:14:44 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Currently only used for the allies. Whilst flying around, the allies will fire on
|
|
|
|
any enemy craft that enter their line of sight.
|
|
|
|
*/
|
2015-03-07 05:18:31 +01:00
|
|
|
int alien_enemiesInFront(object *alien)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
object *anEnemy = enemy;
|
|
|
|
|
|
|
|
for (int i = 0 ; i < MAX_ALIENS ; i++)
|
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien != anEnemy) && (anEnemy->flags & FL_WEAPCO) && (anEnemy->shield > 0))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->y > anEnemy->y - 15) && (alien->y < anEnemy->y + anEnemy->image[0]->h + 15))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->face == 1) && (anEnemy->x < alien->x))
|
2011-08-24 14:14:44 +02:00
|
|
|
return 1;
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->face == 0) && (anEnemy->x > alien->x))
|
2011-08-24 14:14:44 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-24 14:44:40 +02:00
|
|
|
anEnemy++;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-07 05:18:31 +01:00
|
|
|
void alien_move(object *alien)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
bool checkCollisions;
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->flags & FL_LEAVESECTOR) || (alien->shield < 1))
|
2011-08-26 16:55:46 +02:00
|
|
|
checkCollisions = false;
|
2015-03-06 15:37:21 +01:00
|
|
|
else
|
|
|
|
checkCollisions = true;
|
2011-08-24 14:14:44 +02:00
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if (alien->owner == alien)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
if (alien->flags & FL_CIRCLES)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
if (alien->face == 0)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
alien->dx += 0.02;
|
|
|
|
alien->dy += 0.02;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
alien->dx -= 0.02;
|
|
|
|
alien->dy -= 0.02;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
alien->x -= (sinf(alien->dx) * 4);
|
|
|
|
alien->y -= (cosf(alien->dy) * 4);
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
alien->x -= alien->dx;
|
|
|
|
alien->y -= alien->dy;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object *anEnemy = enemy;
|
|
|
|
|
|
|
|
if (checkCollisions)
|
|
|
|
{
|
|
|
|
for (int i = 0 ; i < MAX_ALIENS ; i++)
|
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((alien->flags & FL_LEAVESECTOR) || (alien->classDef == CD_DRONE) || (alien->classDef == CD_ASTEROID2) || (alien->owner == anEnemy->owner) || (alien->owner->owner == anEnemy->owner) || (anEnemy->shield < 1))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2011-08-24 14:44:40 +02:00
|
|
|
anEnemy++;
|
2011-08-24 14:14:44 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if (collision(alien, anEnemy))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((anEnemy->classDef == CD_BARRIER) && (anEnemy->owner != alien))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
alien->shield--;
|
|
|
|
alien->hit = 3;
|
|
|
|
alien->dx *= -1;
|
|
|
|
alien->dy *= -1;
|
|
|
|
playSound(SFX_HIT, alien->x);
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-24 14:44:40 +02:00
|
|
|
anEnemy++;
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle a collision with the player
|
2015-03-06 15:37:21 +01:00
|
|
|
if ((player.shield > 0) && (alien->shield > 0) && (checkCollisions))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
if (collision(alien, &player))
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
2015-03-06 15:37:21 +01:00
|
|
|
if (alien->classDef == CD_ASTEROID)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
if (!engine.cheatShield)
|
2015-03-06 15:37:21 +01:00
|
|
|
player.shield -= alien->shield;
|
|
|
|
alien->shield = 0;
|
|
|
|
playSound(SFX_EXPLOSION, alien->x);
|
2011-08-24 14:14:44 +02:00
|
|
|
setInfoLine("Warning: Asteroid Collision Damage!!", FONT_RED);
|
|
|
|
player.hit = 5;
|
2012-03-02 23:00:35 +01:00
|
|
|
playSound(SFX_HIT, player.x);
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if (alien->classDef == CD_ASTEROID2)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
if (!engine.cheatShield)
|
2015-03-06 15:37:21 +01:00
|
|
|
player.shield -= alien->shield;
|
|
|
|
alien->shield = 0;
|
|
|
|
playSound(SFX_EXPLOSION, alien->x);
|
2011-08-24 14:14:44 +02:00
|
|
|
setInfoLine("Warning: Asteroid Collision Damage!!", FONT_RED);
|
|
|
|
player.hit = 5;
|
2012-03-02 23:00:35 +01:00
|
|
|
playSound(SFX_HIT, player.x);
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
|
2015-03-06 15:37:21 +01:00
|
|
|
if (alien->classDef == CD_BARRIER)
|
2011-08-24 14:14:44 +02:00
|
|
|
{
|
|
|
|
if (!engine.cheatShield)
|
|
|
|
player.shield--;
|
|
|
|
player.hit = 5;
|
2012-03-02 23:00:35 +01:00
|
|
|
playSound(SFX_HIT, player.x);
|
2011-08-24 14:14:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|