tbftss/src/battle/player.c

538 lines
10 KiB
C
Raw Normal View History

2015-10-20 13:51:49 +02:00
/*
Copyright (C) 2015 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 "player.h"
static void selectTarget(void);
static void switchGuns(void);
static void cycleRadarZoom(void);
static void selectMissionTarget(void);
static void selectNewPlayer(int dir);
static void initPlayerSelect(void);
static void activateBoost(void);
2015-11-16 00:23:03 +01:00
static void deactivateBoost(void);
static void activateECM(void);
2015-11-23 15:52:11 +01:00
static void handleKeyboard(void);
static void faceMouse(void);
static void handleMouse(void);
2015-12-14 12:41:43 +01:00
static void preFireMissile(void);
static int selectedPlayerIndex;
static int availableGuns[BT_MAX];
static Entity *availablePlayerUnits[MAX_SELECTABLE_PLAYERS];
void initPlayer(void)
{
int i, n;
memset(&availableGuns, 0, sizeof(int) * BT_MAX);
battle.numPlayerGuns = 0;
player->selectedGunType = -1;
2015-12-14 15:05:02 +01:00
if (!player->combinedGuns)
{
2015-12-14 15:05:02 +01:00
for (i = 0 ; i < MAX_FIGHTER_GUNS ; i++)
{
2015-12-14 15:05:02 +01:00
n = player->guns[i].type;
2015-12-14 15:05:02 +01:00
if (n)
{
if (!availableGuns[n])
{
battle.numPlayerGuns++;
}
2015-12-14 15:05:02 +01:00
availableGuns[n] = 1;
if (player->selectedGunType == -1)
{
player->selectedGunType = n;
}
}
}
}
2015-12-14 15:05:02 +01:00
else
{
player->selectedGunType = 0;
}
STRNCPY(player->name, "Player", MAX_NAME_LENGTH);
player->action = NULL;
2015-11-15 18:12:04 +01:00
battle.boostTimer = BOOST_RECHARGE_TIME;
battle.ecmTimer = ECM_RECHARGE_TIME;
2015-11-17 08:23:50 +01:00
game.stats[STAT_EPIC_KILL_STREAK] = MAX(game.stats[STAT_EPIC_KILL_STREAK], battle.stats[STAT_EPIC_KILL_STREAK]);
battle.stats[STAT_EPIC_KILL_STREAK] = 0;
2015-11-26 10:53:49 +01:00
setMouse(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
}
2015-10-20 13:51:49 +02:00
void doPlayer(void)
{
2015-11-15 18:12:04 +01:00
battle.boostTimer = MIN(battle.boostTimer + 1, BOOST_RECHARGE_TIME);
battle.ecmTimer = MIN(battle.ecmTimer + 1, ECM_RECHARGE_TIME);
2015-10-20 13:51:49 +02:00
if (player != NULL)
{
self = player;
if (player->alive == ALIVE_ALIVE)
{
2015-11-23 15:52:11 +01:00
handleKeyboard();
handleMouse();
2015-12-10 11:16:44 +01:00
if (!player->target || player->target->health <= 0 || player->target->systemPower <= 0)
{
selectTarget();
}
2015-11-23 15:52:11 +01:00
}
player->angle = ((int)player->angle) % 360;
if (player->health <= 0 && battle.status == MS_IN_PROGRESS)
{
if (!battle.epic)
2015-10-20 13:51:49 +02:00
{
2015-11-23 15:52:11 +01:00
failMission();
2015-10-20 13:51:49 +02:00
}
2015-11-23 15:52:11 +01:00
else if (player->health == -FPS)
2015-10-20 13:51:49 +02:00
{
2015-11-23 15:52:11 +01:00
initPlayerSelect();
2015-10-20 13:51:49 +02:00
}
2015-11-23 15:52:11 +01:00
}
if (battle.status == MS_IN_PROGRESS)
{
selectMissionTarget();
}
2015-12-18 11:12:37 +01:00
if (dev.playerUnlimitedMissiles)
{
player->missiles = 999;
}
2015-11-23 15:52:11 +01:00
}
if (battle.boostTimer == (int)BOOST_FINISHED_TIME)
{
deactivateBoost();
}
}
static void handleKeyboard(void)
{
if (battle.status == MS_IN_PROGRESS)
{
if (app.keyboard[SDL_SCANCODE_W])
2015-11-23 15:52:11 +01:00
{
if (battle.boostTimer == BOOST_RECHARGE_TIME)
{
playSound(SND_BOOST);
activateBoost();
}
else
{
playSound(SND_GUI_DENIED);
}
2015-11-23 15:52:11 +01:00
app.keyboard[SDL_SCANCODE_W] = 0;
2015-11-23 15:52:11 +01:00
}
2015-11-26 10:53:49 +01:00
if (app.keyboard[SDL_SCANCODE_A])
2015-11-23 15:52:11 +01:00
{
2015-11-26 10:53:49 +01:00
selectTarget();
2015-11-23 15:52:11 +01:00
2015-11-26 10:53:49 +01:00
app.keyboard[SDL_SCANCODE_A] = 0;
}
if (app.keyboard[SDL_SCANCODE_D])
2015-11-26 10:53:49 +01:00
{
if (battle.ecmTimer == ECM_RECHARGE_TIME)
{
playSound(SND_ECM);
activateECM();
}
else
{
playSound(SND_GUI_DENIED);
}
app.keyboard[SDL_SCANCODE_D] = 0;
2015-11-23 15:52:11 +01:00
}
2015-11-28 16:30:41 +01:00
if (app.keyboard[SDL_SCANCODE_S])
2015-11-23 15:52:11 +01:00
{
2015-11-26 10:53:49 +01:00
applyFighterBrakes();
2015-11-23 15:52:11 +01:00
}
2015-12-14 12:41:43 +01:00
if (app.keyboard[SDL_SCANCODE_Z])
{
switchGuns();
app.keyboard[SDL_SCANCODE_Z] = 0;
}
if (app.keyboard[SDL_SCANCODE_X])
{
cycleRadarZoom();
app.keyboard[SDL_SCANCODE_X] = 0;
}
if (app.keyboard[SDL_SCANCODE_SPACE])
{
preFireMissile();
app.keyboard[SDL_SCANCODE_SPACE] = 0;
}
2015-11-23 15:52:11 +01:00
}
}
static void handleMouse(void)
{
faceMouse();
if (battle.status == MS_IN_PROGRESS)
{
if (app.mouse.button[SDL_BUTTON_LEFT] && !player->reload && player->guns[0].type)
{
if (player->selectedGunType != BT_ROCKET)
{
fireGuns(player);
}
else
{
fireRocket(player);
}
2015-11-23 15:52:11 +01:00
}
if (app.mouse.button[SDL_BUTTON_RIGHT])
{
if (battle.boostTimer > BOOST_FINISHED_TIME)
2015-10-20 13:51:49 +02:00
{
2015-11-23 15:52:11 +01:00
applyFighterThrust();
}
2015-10-20 13:51:49 +02:00
}
2015-12-14 12:41:43 +01:00
if (app.mouse.button[SDL_BUTTON_MIDDLE])
2015-10-20 13:51:49 +02:00
{
2015-12-14 12:41:43 +01:00
preFireMissile();
2015-11-23 15:52:11 +01:00
app.mouse.button[SDL_BUTTON_MIDDLE] = 0;
2015-10-20 13:51:49 +02:00
}
if (app.mouse.button[SDL_BUTTON_X1])
{
2015-11-26 18:41:25 +01:00
cycleRadarZoom();
app.mouse.button[SDL_BUTTON_X1] = 0;
}
if (app.mouse.button[SDL_BUTTON_X2])
{
2015-11-26 18:41:25 +01:00
switchGuns();
app.mouse.button[SDL_BUTTON_X2] = 0;
}
2015-10-20 13:51:49 +02:00
}
2015-11-23 15:52:11 +01:00
}
static void faceMouse(void)
{
int dir;
int x, y, wantedAngle;
2015-11-16 00:23:03 +01:00
2015-11-23 15:52:11 +01:00
x = player->x - battle.camera.x;
y = player->y - battle.camera.y;
wantedAngle = getAngle(x, y, app.mouse.x, app.mouse.y);
wantedAngle %= 360;
if (fabs(wantedAngle - player->angle) > 2)
2015-11-16 00:23:03 +01:00
{
2015-11-23 15:52:11 +01:00
dir = ((int)(wantedAngle - player->angle + 360)) % 360 > 180 ? -1 : 1;
player->angle += dir * 4;
player->angle = mod(player->angle, 360);
2015-11-16 00:23:03 +01:00
}
}
2015-12-14 12:41:43 +01:00
static void preFireMissile(void)
{
if (player->missiles && player->target)
{
if (getDistance(player->x, player->y, player->target->x, player->target->y) <= SCREEN_WIDTH)
{
fireMissile(player);
}
else
{
addHudMessage(colors.white, "Target not in range");
}
}
}
void initPlayerSelect(void)
{
Entity *e;
memset(&availablePlayerUnits, 0, sizeof(Entity*) * MAX_SELECTABLE_PLAYERS);
selectedPlayerIndex = 0;
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
2015-11-19 13:44:56 +01:00
if (e->active && e->type == ET_FIGHTER && e->health > 0 && e->side == SIDE_ALLIES && selectedPlayerIndex < MAX_SELECTABLE_PLAYERS)
{
availablePlayerUnits[selectedPlayerIndex++] = e;
}
}
if (selectedPlayerIndex > 0)
{
battle.playerSelect = 1;
selectedPlayerIndex = 0;
memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS);
}
else
{
battle.epic = 0;
2015-11-14 09:41:31 +01:00
failMission();
}
}
void doPlayerSelect(void)
{
if (app.keyboard[SDL_SCANCODE_A] || app.mouse.button[SDL_BUTTON_X1])
{
selectNewPlayer(-1);
app.mouse.button[SDL_BUTTON_X1] = app.keyboard[SDL_SCANCODE_A] = 0;
}
if (app.keyboard[SDL_SCANCODE_D] || app.mouse.button[SDL_BUTTON_X2])
{
selectNewPlayer(1);
app.mouse.button[SDL_BUTTON_X2] = app.keyboard[SDL_SCANCODE_D] = 0;
}
if (player->health > 0 && app.mouse.button[SDL_BUTTON_LEFT])
{
battle.playerSelect = 0;
initPlayer();
app.mouse.button[SDL_BUTTON_LEFT] = 0;
}
}
static void selectNewPlayer(int dir)
{
do
{
selectedPlayerIndex += dir;
selectedPlayerIndex = mod(selectedPlayerIndex, MAX_SELECTABLE_PLAYERS);
player = availablePlayerUnits[selectedPlayerIndex];
}
while (player == NULL);
battle.camera.x = player->x - (SCREEN_WIDTH / 2);
battle.camera.y = player->y - (SCREEN_HEIGHT / 2);
2015-10-20 13:51:49 +02:00
}
static void activateBoost(void)
{
self->dx += sin(TO_RAIDANS(self->angle)) * 10;
self->dy += -cos(TO_RAIDANS(self->angle)) * 10;
self->thrust = sqrt((self->dx * self->dx) + (self->dy * self->dy));
2015-11-15 18:12:04 +01:00
battle.boostTimer = 0;
2015-11-17 08:23:50 +01:00
battle.stats[STAT_BOOST]++;
}
2015-11-16 00:23:03 +01:00
static void deactivateBoost(void)
{
float v, thrust;
thrust = -1;
while (thrust != self->thrust)
{
thrust = self->thrust;
v = (self->speed / sqrt(self->thrust));
self->dx = v * self->dx;
self->dy = v * self->dy;
self->thrust = sqrt((self->dx * self->dx) + (self->dy * self->dy));
}
}
static void activateECM(void)
{
2015-11-15 18:12:04 +01:00
battle.ecmTimer = 0;
2015-11-17 08:23:50 +01:00
2015-11-29 09:34:25 +01:00
addECMEffect(player);
2015-11-17 08:23:50 +01:00
battle.stats[STAT_ECM]++;
}
static void switchGuns(void)
{
int i;
i = player->selectedGunType;
2015-12-14 15:05:02 +01:00
if (!player->combinedGuns)
{
2015-12-14 15:05:02 +01:00
do
{
i = (i + 1) % BT_MAX;
}
while (!availableGuns[i]);
}
2016-02-20 16:04:15 +01:00
if (player->selectedGunType != i)
{
playSound(SND_SELECT_WEAPON);
player->selectedGunType = i;
}
}
2015-10-20 13:51:49 +02:00
static void selectTarget(void)
{
2015-11-01 11:46:24 +01:00
unsigned int closest = MAX_TARGET_RANGE;
unsigned int dist = MAX_TARGET_RANGE;
2015-11-23 11:14:28 +01:00
int i, total;
Entity *e, *near;
Entity *targets[MAX_SELECTABLE_TARGETS];
2015-10-20 13:51:49 +02:00
2015-11-23 11:14:28 +01:00
i = 0;
2015-11-23 15:52:11 +01:00
near = NULL;
2015-11-23 11:14:28 +01:00
memset(targets, 0, sizeof(Entity*) * MAX_SELECTABLE_TARGETS);
2015-10-20 13:51:49 +02:00
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
2015-10-20 13:51:49 +02:00
{
2015-12-09 08:25:24 +01:00
if (e->active && e != player && (e->flags & EF_TAKES_DAMAGE) && e->side != player->side && e->alive == ALIVE_ALIVE && (!(e->flags & EF_DISABLED)) && i < MAX_SELECTABLE_TARGETS)
2015-10-20 13:51:49 +02:00
{
dist = getDistance(self->x, self->y, e->x, e->y);
2015-10-20 13:51:49 +02:00
if (dist < closest)
{
2015-11-23 11:14:28 +01:00
near = e;
2015-10-20 13:51:49 +02:00
closest = dist;
}
2015-11-23 11:14:28 +01:00
if (collision(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, e->x - battle.camera.x - (e->w / 2), e->y - battle.camera.y - (e->h / 2), e->w, e->h))
{
targets[i++] = e;
}
else if (e == player->target)
{
player->target = NULL;
}
2015-10-20 13:51:49 +02:00
}
}
2015-11-23 11:14:28 +01:00
total = i;
for (i = 0 ; i < total ; i++)
{
if (targets[i] == player->target)
{
if (i + 1 < MAX_SELECTABLE_TARGETS && targets[i + 1])
{
player->target = targets[i + 1];
return;
}
else
{
player->target = targets[0];
}
}
}
2015-12-10 11:16:44 +01:00
if (!player->target || !targets[0])
2015-11-23 11:14:28 +01:00
{
player->target = near;
}
2015-10-20 13:51:49 +02:00
}
static void selectMissionTarget(void)
{
2015-11-01 11:46:24 +01:00
unsigned int closest = MAX_TARGET_RANGE;
unsigned int dist = MAX_TARGET_RANGE;
Entity *e;
battle.missionTarget = NULL;
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (e->active && e->flags & EF_MISSION_TARGET && e->alive == ALIVE_ALIVE)
{
2015-11-22 12:42:04 +01:00
dist = getDistance(self->x, self->y, e->x, e->y);
if (battle.missionTarget == NULL)
{
battle.missionTarget = e;
2015-11-22 12:42:04 +01:00
closest = dist;
}
else if (battle.missionTarget->type == ET_WAYPOINT && e->type != ET_WAYPOINT)
{
battle.missionTarget = e;
}
else if (battle.missionTarget->type != ET_WAYPOINT)
{
if (dist < closest)
{
battle.missionTarget = e;
closest = dist;
}
}
else if (battle.missionTarget->type == ET_WAYPOINT && e->type == ET_WAYPOINT && e->id < battle.missionTarget->id)
{
battle.missionTarget = e;
}
}
}
}
static void cycleRadarZoom(void)
{
2015-11-26 11:54:40 +01:00
battle.radarRange++;
battle.radarRange %= 3;
}
2016-02-20 16:04:15 +01:00
int playerHasGun(int type)
{
return availableGuns[type];
}