Added Blob Bosses code; Blaze and Frost.

This commit is contained in:
Steve 2018-01-26 07:56:12 +00:00
parent 7a2529d250
commit 9e9de85e7e
20 changed files with 668 additions and 51 deletions

View File

@ -12,6 +12,7 @@ SEARCHPATH += src/widgets
SEARCHPATH += src/world
SEARCHPATH += src/world/entities
SEARCHPATH += src/world/entities/blobs
SEARCHPATH += src/world/entities/boss
vpath %.c $(SEARCHPATH)
vpath %.h $(SEARCHPATH)
@ -19,9 +20,11 @@ vpath %.h $(SEARCHPATH)
DEPS += defs.h structs.h
OBJS += atlas.o
OBJS += blaze.o boss.o blobBoss.o
OBJS += camera.o combat.o
OBJS += draw.o
OBJS += effects.o entities.o explosions.o
OBJS += frost.o
OBJS += game.o
OBJS += hub.o hud.o
OBJS += init.o input.o io.o items.o

View File

@ -55,11 +55,11 @@ void addExplosion(float x, float y, int radius, Entity *owner)
{
if (e->flags & EF_BOMB_SHIELD)
{
applyEntityDamage(e, 2);
e->applyDamage(2);
}
else
{
applyEntityDamage(e, (int) power);
e->applyDamage((int) power);
}
if (e->type == ET_BOB)

View File

@ -80,6 +80,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_OXYGEN (FPS * 10)
#define MAX_KEY_TYPES 12
#define MAX_CHECKPOINTS 15
#define MAX_WIDGET_OPTIONS 8
enum
@ -268,6 +270,7 @@ enum
CH_PLAYER,
CH_EXPLODE,
CH_WEAPON,
CH_DEATH,
CH_MAX
};

View File

@ -38,6 +38,34 @@ void initGame(void)
game.timePlayed = 0;
}
void addRescuedMIA(char *name)
{
int i;
for (i = 0 ; i < game.totalMIAs ; i++)
{
if (strcmp(game.mias[i], "") == 0)
{
STRNCPY(game.mias[i], name, MAX_NAME_LENGTH);
return;
}
}
}
void addDefeatedTarget(char *name)
{
int i;
for (i = 0 ; i < game.totalTargets ; i++)
{
if (strcmp(game.targets[i], "") == 0)
{
STRNCPY(game.targets[i], name, MAX_NAME_LENGTH);
return;
}
}
}
/*
public void updateTimePlayedString()
{

View File

@ -55,6 +55,11 @@ struct Texture {
Texture *next;
};
typedef struct {
float x;
float y;
} PointF;
typedef struct {
SDL_Color red;
SDL_Color orange;
@ -120,6 +125,8 @@ struct Entity {
int shudderTimer;
int starTimer;
int teleportTimer;
int stunTimer;
int weakAgainst;
long flags;
SDL_Rect bounds;
int sprite[3];
@ -127,12 +134,18 @@ struct Entity {
int spriteFrame;
Entity *carriedItem;
Entity *owner;
void (*currentAction)(void);
void (*action)(void);
void (*walk)(void);
void (*attack)(void);
void (*touch)(Entity *other);
void (*tick)(void);
void (*die)(void);
void (*reset)(void);
void (*activate)(int active);
void (*changeEnvironment)(void);
int (*getCurrentSprite)(void);
void (*animate)(void);
void (*applyDamage)(int amount);
Entity *next;
};
@ -309,7 +322,7 @@ struct Particle {
};
typedef struct {
Entity *bob;
Entity *bob, *boss;
Map map;
Entity entityHead, *entityTail;
Particle particleHead, *particleTail;
@ -317,7 +330,9 @@ typedef struct {
int frameCounter;
int currentStatus;
int isBossMission;
int isBossActive;
int isOutpostMission;
PointF checkpoints[MAX_CHECKPOINTS];
Quadtree quadtree;
Objective objectiveHead, *objectiveTail;
Trigger triggerHead, *triggerTail;

View File

@ -73,6 +73,11 @@ void playSound(int snd, int ch)
Mix_PlayChannel(ch, sounds[snd], 0);
}
int isPlayingMusic(void)
{
return 0;
}
static Mix_Chunk *loadSound(char *filename)
{
return Mix_LoadWAV(getFileLocation(filename));

View File

@ -25,7 +25,6 @@ static void tick(void);
static void touch(Entity *other);
static void preTeleport(void);
static void teleport(void);
static void addRescuedMIA(void);
void initMIA(Entity *e)
{
@ -41,7 +40,7 @@ void initMIA(Entity *e)
e->spriteFrame = 0;
e->spriteTime = rand() % 180;
e->currentAction = nothing;
e->action = nothing;
e->reset = reset;
e->tick = tick;
e->touch = touch;
@ -72,7 +71,7 @@ static void tick(void)
self->shudderTimer = 2;
}
if (self->currentAction != nothing)
if (self->action != nothing)
{
self->starTimer--;
if (self->starTimer <= 0)
@ -85,9 +84,9 @@ static void tick(void)
static void touch(Entity *other)
{
if (self->currentAction == nothing && other == world.bob)
if (self->action == nothing && other == world.bob)
{
self->currentAction = preTeleport;
self->action = preTeleport;
self->teleportTimer = FPS * 3;
setGameplayMessage(MSG_OBJECTIVE, "Rescued %s", self->name);
self->isMissionTarget = 0;
@ -101,7 +100,7 @@ static void preTeleport(void)
self->teleportTimer--;
if (self->teleportTimer <= FPS)
{
self->currentAction = teleport;
self->action = teleport;
self->flags |= (EF_NO_CLIP | EF_WEIGHTLESS);
self->dy = -5;
}
@ -113,22 +112,8 @@ static void teleport(void)
if (self->teleportTimer <= 0)
{
addTeleportStars(self);
addRescuedMIA();
addRescuedMIA(self->name);
updateObjective("MIA");
self->alive = ALIVE_DEAD;
}
}
static void addRescuedMIA(void)
{
int i;
for (i = 0 ; i < game.totalMIAs ; i++)
{
if (strcmp(game.mias[i], "") == 0)
{
STRNCPY(game.mias[i], self->name, MAX_NAME_LENGTH);
return;
}
}
}

View File

@ -27,6 +27,7 @@ extern void addTeleportStars(Entity *e);
extern void setGameplayMessage(int type, char *format, ...);
extern void playSound(int snd, int ch);
extern void updateObjective(char *targetName);
extern void addRescuedMIA(char *name);
extern Entity *self;
extern Game game;

View File

@ -37,7 +37,7 @@ void initTeeka(Entity *e)
e->flags |= EF_IMMUNE;
e->currentAction = lookForEnemies;
e->action = lookForEnemies;
e->weaponType = WPN_AIMED_PISTOL;
@ -62,7 +62,7 @@ static void tick(void)
{
target = NULL;
self->currentAction = lookForEnemies;
self->action = lookForEnemies;
}
}
@ -101,7 +101,7 @@ static void lookForEnemies(void)
{
self->shotsToFire = rrnd(3, 5);
self->currentAction = preFire;
self->action = preFire;
}
else if (exitMission)
{

View File

@ -0,0 +1,34 @@
/*
Copyright (C) 2018 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 "blaze.h"
void initBlaze(Entity *e)
{
initBlobBoss(e);
e->weakAgainst = ENV_WATER;
STRNCPY(e->name, "Blaze", MAX_NAME_LENGTH);
e->sprite[FACING_LEFT] = getSpriteIndex("BlazeLeft");
e->sprite[FACING_RIGHT] = getSpriteIndex("BlazeRight");
e->sprite[FACING_DIE] = getSpriteIndex("BlazeSpin");
}

View File

@ -0,0 +1,24 @@
/*
Copyright (C) 2018 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 "../../../common.h"
extern void initBlobBoss(Entity *e);
extern int getSpriteIndex(char *name);

View File

@ -0,0 +1,346 @@
/*
Copyright (C) 2018 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 "blobBoss.h"
static void activate(int activate);
static void tick(void);
static void changeEnvironment(void);
static int getCurrentSprite(void);
static void animate(void);
static void applyDamage(int amount);
static void moveTowardsPlayer(void);
static void preFire(void);
static void teleport(void);
static void attack(void);
static void die1(void);
static void die2(void);
static int aimedSprite;
void initBlobBoss(Entity *e)
{
initBoss(e);
aimedSprite = getSpriteIndex("AimedShot");
e->flags |= EF_HALT_AT_EDGE;
e->health = e->healthMax = 250;
e->teleportTimer = FPS * rrnd(4, 6);
e->activate = activate;
e->tick = tick;
e->changeEnvironment = changeEnvironment;
e->getCurrentSprite = getCurrentSprite;
e->animate = animate;
e->applyDamage = applyDamage;
e->die = die1;
}
static void activate(int activate)
{
self->flags &= ~EF_GONE;
world.isBossActive = 1;
addTeleportStars(self);
if (!isPlayingMusic())
{
playMusic("", 1);
}
}
static void tick(void)
{
if (self->health > 0)
{
self->stunTimer = MAX(self->stunTimer - 1, 0);
if (self->environment == self->weakAgainst)
{
self->health -= 2;
world.boss = self;
}
if (self->stunTimer == 0)
{
self->facing = (world.bob->x < self->x) ? FACING_LEFT : FACING_RIGHT;
self->reload = limit(--self->reload, 0, FPS);
self->teleportTimer = limit(self->teleportTimer - 1, 0, 9999);
if (self->isOnGround)
{
self->flags |= EF_HALT_AT_EDGE;
}
else
{
self->flags &= ~EF_HALT_AT_EDGE;
}
}
}
}
static void changeEnvironment()
{
if (self->environment == self->weakAgainst)
{
self->teleportTimer = 0;
self->stunTimer = 90;
self->spriteFrame = self->spriteTime = 0;
}
else
{
self->teleportTimer = 0;
}
}
static void die1(void)
{
self->flags |= EF_BOUNCES;
self->thinkTime = 0;
self->spriteTime = 0;
self->spriteFrame = 0;
if (self->environment == ENV_AIR)
{
self->dy = -9;
}
self->dx = (randF() - randF()) * 5;
self->flags &= ~EF_HALT_AT_EDGE;
switch (rand() % 3)
{
case 0:
playSound(SND_DEATH_1, CH_DEATH);
break;
case 1:
playSound(SND_DEATH_2, CH_DEATH);
break;
case 2:
playSound(SND_DEATH_3, CH_DEATH);
break;
}
self->action = die2;
}
static int getCurrentSprite(void)
{
if (self->stunTimer > 0 || self->health <= 0)
{
return self->sprite[FACING_DIE];
}
return self->sprite[self->facing];
}
static void animate(void)
{
if (self->dx != 0 || self->health <= 0 || self->stunTimer > 0)
{
animateEntity(self);
}
}
static void lookForPlayer(void)
{
self->thinkTime = rrnd(0, FPS / 2);
if (getDistance(world.bob->x, world.bob->y, self->x, self->y) > 650)
{
moveTowardsPlayer();
return;
}
if (!enemyCanSeePlayer(self))
{
moveTowardsPlayer();
return;
}
if (rand() % 100 < 15)
{
self->shotsToFire = rrnd(1, 12);
self->action = preFire;
}
moveTowardsPlayer();
}
static void moveTowardsPlayer(void)
{
self->dx = 0;
if (rand() % 100 < 20)
{
if (world.bob->x < self->x)
{
self->dx = -3.5;
}
if (world.bob->x > self->x)
{
self->dx = 3.5;
}
if (world.bob->y <= self->y && rand() % 2 == 0 && self->isOnGround)
{
self->dy = JUMP_POWER;
}
}
if (self->stunTimer == 0 && self->teleportTimer == 0)
{
teleport();
self->teleportTimer = FPS * rrnd(4, 6);
}
}
static void preFire(void)
{
if (self->reload > 0)
{
return;
}
attack();
self->shotsToFire--;
if (self->shotsToFire == 0)
{
self->walk();
}
}
static void attack(void)
{
Entity *bullet;
float dx, dy;
int bx, by;
bx = (int) (world.bob->x + rrnd(-8, 24));
by = (int) (world.bob->y + rrnd(-8, 24));
getSlope(bx, by, self->x, self->y, &dx, &dy);
bullet = createBaseBullet(self);
bullet->x = self->x;
bullet->y = (self->y + self->h / 2) - 3;
bullet->facing = self->facing;
bullet->damage = 1;
bullet->owner = self;
bullet->health = FPS * 3;
bullet->weaponType = WPN_AIMED_PISTOL;
bullet->dx = dx * 12;
bullet->dy = dy * 12;
bullet->sprite[0] = bullet->sprite[1] = aimedSprite;
self->reload = 4;
playSound(SND_MACHINE_GUN, CH_WEAPON);
}
static void walk(void)
{
self->action = (self->health > 0) ? lookForPlayer : die2;
}
void reappear(void)
{
int valid, r;
valid = 0;
do
{
r = (int) (rand() % MAX_CHECKPOINTS);
self->x = world.checkpoints[r].x;
self->y = world.checkpoints[r].y;
valid = (self->x != 0 && self->y != 0);
}
while (!valid);
self->y -= (self->h + 10);
walk();
self->flags &= ~EF_GONE;
addTeleportStars(self);
playSound(SND_APPEAR, CH_ANY);
}
static void applyDamage(int amount)
{
self->health -= amount;
self->thinkTime = 0;
if (rand() % 10 == 0)
{
teleport();
}
world.boss = self;
}
static void teleport(void)
{
self->action = reappear;
self->flags |= EF_GONE;
self->thinkTime = FPS * rrnd(3, 6);
addTeleportStars(self);
playSound(SND_APPEAR, CH_ANY);
}
static void die2(void)
{
self->health--;
if (self->health <= -FPS)
{
addTeleportStars(self);
playSound(SND_APPEAR, CH_ANY);
self->alive = ALIVE_DEAD;
updateObjective(self->name);
addDefeatedTarget(self->name);
game.enemiesKilled++;
}
}

View File

@ -0,0 +1,42 @@
/*
Copyright (C) 2018 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 "../../../common.h"
extern void initBoss(Entity *e);
extern int rrnd(int low, int high);
extern void addTeleportStars(Entity *e);
extern void playMusic(char *filename, int loop);
extern int isPlayingMusic(void);
extern float limit(float i, float a, float b);
extern double randF(void);
extern void playSound(int snd, int ch);
extern void animateEntity(Entity *e);
extern Entity *createBaseBullet(Entity *owner);
extern int getSpriteIndex(char *name);
extern int getDistance(int x1, int y1, int x2, int y2);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern int enemyCanSeePlayer(Entity *e);
extern void updateObjective(char *targetName);
extern void addDefeatedTarget(char *name);
extern Entity *self;
extern Game game;
extern World world;

View File

@ -0,0 +1,39 @@
/*
Copyright (C) 2018 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 "boss.h"
void initBoss(Entity *e)
{
initEntity(e);
e->sprite[FACING_LEFT] = e->sprite[FACING_RIGHT] = e->sprite[FACING_DIE] = getSpriteIndex("Boss");
e->isMissionTarget = 1;
e->action = lookForPlayer;
e->spriteFrame = 0;
e->spriteTime = 0;
world.boss = e;
e->flags |= EF_ALWAYS_PROCESS | EF_BOMB_SHIELD | EF_GONE;
}

View File

@ -0,0 +1,27 @@
/*
Copyright (C) 2018 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 "../../../common.h"
extern void initEntity(Entity *e);
extern void lookForPlayer(void);
extern int getSpriteIndex(char *name);
extern World world;

View File

@ -0,0 +1,34 @@
/*
Copyright (C) 2018 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 "frost.h"
void initFrost(Entity *e)
{
initBlobBoss(e);
e->weakAgainst = ENV_LAVA;
STRNCPY(e->name, "Frost", MAX_NAME_LENGTH);
e->sprite[FACING_LEFT] = getSpriteIndex("FrostLeft");
e->sprite[FACING_RIGHT] = getSpriteIndex("FrostRight");
e->sprite[FACING_DIE] = getSpriteIndex("FrostSpin");
}

View File

@ -0,0 +1,24 @@
/*
Copyright (C) 2018 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 "../../../common.h"
extern void initBlobBoss(Entity *e);
extern int getSpriteIndex(char *name);

View File

@ -20,6 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "entities.h"
void animateEntity(void);
static void applyDamage(int damage);
Entity *createEntity(void)
{
Entity *e;
@ -62,6 +65,9 @@ void initEntity(Entity *e)
e->thinkTime = 0;
e->plane = PLANE_BACKGROUND;
e->animate = animateEntity;
e->applyDamage = applyDamage;
}
SDL_Rect *getEntityBounds(Entity *e)
@ -84,21 +90,21 @@ int getCurrentEntitySprite(Entity *e)
return e->sprite[FACING_DIE];
}
void animateEntity(Entity *e)
void animateEntity(void)
{
Sprite *spr;
if (e->spriteTime != -1)
if (self->spriteTime != -1)
{
e->spriteTime--;
self->spriteTime--;
if (e->spriteTime <= 0)
if (self->spriteTime <= 0)
{
spr = getSpriteByIndex(getCurrentEntitySprite(e));
e->spriteFrame = wrap(e->spriteFrame + 1, 0, 1);
e->spriteTime = 0;
e->w = spr->w;
e->h = spr->h;
spr = getSpriteByIndex(getCurrentEntitySprite(self));
self->spriteFrame = wrap(self->spriteFrame + 1, 0, 1);
self->spriteTime = 0;
self->w = spr->w;
self->h = spr->h;
}
}
}
@ -148,28 +154,28 @@ void activateEntities(char *names, int activate)
{
}
void applyEntityDamage(Entity *e, int damage)
static void applyDamage(int damage)
{
if (e->health < 0)
if (self->health < 0)
{
e->health = 0;
e->alive = ALIVE_ALIVE;
self->health = 0;
self->alive = ALIVE_ALIVE;
}
e->health -= damage;
self->health -= damage;
if (e->health > 0)
if (self->health > 0)
{
e->thinkTime = 0;
self->thinkTime = 0;
e->facing = e->x < world.bob->x ? FACING_RIGHT : FACING_LEFT;
self->facing = self->x < world.bob->x ? FACING_RIGHT : FACING_LEFT;
if (e->isMissionTarget && rand() % 10 == 0)
if (self->isMissionTarget && rand() % 10 == 0)
{
e->currentAction = unitReappear;
e->flags |= EF_GONE;
e->thinkTime = rand() % FPS;
addTeleportStars(e);
self->action = unitReappear;
self->flags |= EF_GONE;
self->thinkTime = rand() % FPS;
addTeleportStars(self);
playSound(SND_APPEAR, CH_ANY);
}
}

View File

@ -26,5 +26,6 @@ extern void addTeleportStars(Entity *e);
extern void unitReappear(void);
extern void playSound(int snd, int ch);
extern Entity *self;
extern Game game;
extern World world;

View File

@ -42,7 +42,7 @@ void initUnit(Entity *e)
e->startX = e->startY = -1;
e->tick = unitTick;
e->currentAction = lookForPlayer;
e->action = lookForPlayer;
e->attack = attack;
}