mirror of
https://github.com/cxong/cdogs-sdl.git
synced 2025-07-23 07:23:01 +02:00
Add lives and respawning (fixes #58)
Fix crash after quitting from player select menu Add event delay attribute
This commit is contained in:
BIN
sounds/spawn.ogg
Normal file
BIN
sounds/spawn.ogg
Normal file
Binary file not shown.
8
sounds/spawn.txt
Normal file
8
sounds/spawn.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Derived from
|
||||
Ambient power chord (E2) by Khoon
|
||||
http://freesound.org/people/Khoon/sounds/168741/
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
and
|
||||
teleport by fins
|
||||
http://freesound.org/people/fins/sounds/172207/
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
@@ -121,7 +121,7 @@ static void AddAndPlacePlayers(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
firstPos = PlacePlayer(&gMap, p, firstPos);
|
||||
firstPos = PlacePlayer(&gMap, p, firstPos, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,6 +391,10 @@ void MainLoop(credits_displayer_t *creditsDisplayer, custom_campaigns_t *campaig
|
||||
gCampaign.IsLoaded ||
|
||||
MainMenu(&gGraphicsDevice, creditsDisplayer, campaigns))
|
||||
{
|
||||
// Reset player datas
|
||||
PlayerDataTerminate(&gPlayerDatas);
|
||||
PlayerDataInit(&gPlayerDatas);
|
||||
|
||||
debug(D_NORMAL, ">> Entering campaign\n");
|
||||
if (IsIntroNeeded(gCampaign.Entry.Mode))
|
||||
{
|
||||
@@ -448,9 +452,6 @@ void MainLoop(credits_displayer_t *creditsDisplayer, custom_campaigns_t *campaig
|
||||
}
|
||||
gCampaign.IsLoaded = false;
|
||||
gCampaign.IsClient = false; // TODO: select is client from menu
|
||||
// Reset player datas
|
||||
PlayerDataTerminate(&gPlayerDatas);
|
||||
PlayerDataInit(&gPlayerDatas);
|
||||
}
|
||||
debug(D_NORMAL, ">> Leaving Main Game Loop\n");
|
||||
|
||||
|
@@ -156,7 +156,8 @@ NetMsgVec2i PlacePrisoner(Map *map)
|
||||
return posNet;
|
||||
}
|
||||
|
||||
Vec2i PlacePlayer(Map *map, const PlayerData *p, const Vec2i firstPos)
|
||||
Vec2i PlacePlayer(
|
||||
Map *map, const PlayerData *p, const Vec2i firstPos, const bool pumpEvents)
|
||||
{
|
||||
NetMsgActorAdd aa = NetMsgActorAdd_init_default;
|
||||
aa.Id = ActorsGetFreeIndex();
|
||||
@@ -187,13 +188,15 @@ Vec2i PlacePlayer(Map *map, const PlayerData *p, const Vec2i firstPos)
|
||||
aa.FullPos = PlaceActor(map);
|
||||
}
|
||||
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_ADD;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_ADD);
|
||||
e.u.ActorAdd = aa;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
|
||||
// Process the events that actually place the players
|
||||
HandleGameEvents(&gGameEvents, NULL, NULL, NULL, &gEventHandlers);
|
||||
if (pumpEvents)
|
||||
{
|
||||
// Process the events that actually place the players
|
||||
HandleGameEvents(&gGameEvents, NULL, NULL, NULL, &gEventHandlers);
|
||||
}
|
||||
|
||||
return Vec2iNew(aa.FullPos.x, aa.FullPos.y);
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@
|
||||
NetMsgVec2i PlaceBaddie(Map *map);
|
||||
NetMsgVec2i PlacePrisoner(Map *map);
|
||||
|
||||
Vec2i PlacePlayer(Map *map, const PlayerData *p, const Vec2i firstPos);
|
||||
Vec2i PlacePlayer(
|
||||
Map *map, const PlayerData *p, const Vec2i firstPos, const bool pumpEvents);
|
||||
|
||||
#endif
|
||||
|
@@ -53,6 +53,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "actor_placement.h"
|
||||
#include "ai_utils.h"
|
||||
#include "character.h"
|
||||
#include "collision.h"
|
||||
@@ -338,8 +339,7 @@ static void CheckTrigger(const Vec2i tilePos)
|
||||
Trigger **tp = CArrayGet(&t->triggers, i);
|
||||
if (TriggerCanActivate(*tp, gMission.flags))
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_TRIGGER;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_TRIGGER);
|
||||
e.u.Trigger.Id = (*tp)->id;
|
||||
e.u.Trigger.TilePos = tilePos;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
@@ -355,8 +355,7 @@ static void PickupObject(TActor * actor, TObject * object)
|
||||
{
|
||||
case OBJ_JEWEL:
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_SCORE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_SCORE);
|
||||
e.u.Score.PlayerIndex = actor->playerIndex;
|
||||
e.u.Score.Score = PICKUP_SCORE;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
@@ -373,8 +372,7 @@ static void PickupObject(TActor * actor, TObject * object)
|
||||
if (actor->health < ActorGetCharacter(actor)->maxHealth)
|
||||
{
|
||||
canPickup = true;
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_TAKE_HEALTH_PICKUP;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_TAKE_HEALTH_PICKUP);
|
||||
e.u.PickupPlayer = actor->playerIndex;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
SoundPlayAt(
|
||||
@@ -540,8 +538,7 @@ bool TryMoveActor(TActor *actor, Vec2i pos)
|
||||
}
|
||||
}
|
||||
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_MOVE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_MOVE);
|
||||
e.u.ActorMove.Id = actor->tileItem.id;
|
||||
e.u.ActorMove.Pos.x = pos.x;
|
||||
e.u.ActorMove.Pos.y = pos.y;
|
||||
@@ -660,8 +657,7 @@ void InjureActor(TActor * actor, int injury)
|
||||
{
|
||||
actor->stateCounter = 0;
|
||||
Vec2i pos = Vec2iNew(actor->tileItem.x, actor->tileItem.y);
|
||||
GameEvent sound;
|
||||
sound.Type = GAME_EVENT_SOUND_AT;
|
||||
GameEvent sound = GameEventNew(GAME_EVENT_SOUND_AT);
|
||||
sound.u.SoundAt.Sound = SoundGetRandomScream(&gSoundDevice);
|
||||
sound.u.SoundAt.Pos = pos;
|
||||
GameEventsEnqueue(&gGameEvents, sound);
|
||||
@@ -694,8 +690,7 @@ void Shoot(TActor *actor)
|
||||
actor->uid);
|
||||
if (actor->playerIndex >= 0 && gun->Gun->Cost != 0)
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_SCORE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_SCORE);
|
||||
e.u.Score.PlayerIndex = actor->playerIndex;
|
||||
e.u.Score.Score = -gun->Gun->Cost;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
@@ -848,6 +843,7 @@ void SlideActor(TActor *actor, int cmd)
|
||||
}
|
||||
|
||||
static void ActorUpdatePosition(TActor *actor, int ticks);
|
||||
static void ActorDie(TActor *actor, const int idx);
|
||||
void UpdateAllActors(int ticks)
|
||||
{
|
||||
for (int i = 0; i < (int)gActors.size; i++)
|
||||
@@ -861,47 +857,38 @@ void UpdateAllActors(int ticks)
|
||||
UpdateActorState(actor, ticks);
|
||||
if (actor->dead > DEATH_MAX)
|
||||
{
|
||||
AddObjectOld(
|
||||
actor->Pos.x, actor->Pos.y,
|
||||
Vec2iZero(),
|
||||
&cBloodPics[rand() % BLOOD_MAX],
|
||||
OBJ_NONE,
|
||||
TILEITEM_IS_WRECK);
|
||||
ActorDestroy(i);
|
||||
ActorDie(actor, i);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
// Find actors that are on the same team and colliding,
|
||||
// and repel them
|
||||
if (gConfig.Game.AllyCollision == ALLYCOLLISION_REPEL)
|
||||
{
|
||||
// Find actors that are on the same team and colliding,
|
||||
// and repel them
|
||||
if (gConfig.Game.AllyCollision == ALLYCOLLISION_REPEL)
|
||||
Vec2i realPos = Vec2iFull2Real(actor->Pos);
|
||||
TTileItem *collidingItem = GetItemOnTileInCollision(
|
||||
&actor->tileItem, realPos, TILEITEM_IMPASSABLE,
|
||||
COLLISIONTEAM_NONE,
|
||||
gCampaign.Entry.Mode == CAMPAIGN_MODE_DOGFIGHT);
|
||||
if (collidingItem && collidingItem->kind == KIND_CHARACTER)
|
||||
{
|
||||
Vec2i realPos = Vec2iFull2Real(actor->Pos);
|
||||
TTileItem *collidingItem = GetItemOnTileInCollision(
|
||||
&actor->tileItem, realPos, TILEITEM_IMPASSABLE,
|
||||
COLLISIONTEAM_NONE,
|
||||
gCampaign.Entry.Mode == CAMPAIGN_MODE_DOGFIGHT);
|
||||
if (collidingItem && collidingItem->kind == KIND_CHARACTER)
|
||||
TActor *collidingActor = CArrayGet(
|
||||
&gActors, collidingItem->id);
|
||||
if (CalcCollisionTeam(1, collidingActor) ==
|
||||
CalcCollisionTeam(1, actor))
|
||||
{
|
||||
TActor *collidingActor = CArrayGet(
|
||||
&gActors, collidingItem->id);
|
||||
if (CalcCollisionTeam(1, collidingActor) ==
|
||||
CalcCollisionTeam(1, actor))
|
||||
Vec2i v = Vec2iMinus(actor->Pos, collidingActor->Pos);
|
||||
if (Vec2iIsZero(v))
|
||||
{
|
||||
Vec2i v = Vec2iMinus(actor->Pos, collidingActor->Pos);
|
||||
if (Vec2iIsZero(v))
|
||||
{
|
||||
v = Vec2iNew(1, 0);
|
||||
}
|
||||
v = Vec2iScale(Vec2iNorm(v), REPEL_STRENGTH);
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_IMPULSE;
|
||||
e.u.ActorImpulse.Id = actor->tileItem.id;
|
||||
e.u.ActorImpulse.Vel = v;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
e.u.ActorImpulse.Id = collidingActor->tileItem.id;
|
||||
e.u.ActorImpulse.Vel = Vec2iScale(v, -1);
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
v = Vec2iNew(1, 0);
|
||||
}
|
||||
v = Vec2iScale(Vec2iNorm(v), REPEL_STRENGTH);
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_IMPULSE);
|
||||
e.u.ActorImpulse.Id = actor->tileItem.id;
|
||||
e.u.ActorImpulse.Vel = v;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
e.u.ActorImpulse.Id = collidingActor->tileItem.id;
|
||||
e.u.ActorImpulse.Vel = Vec2iScale(v, -1);
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -941,6 +928,50 @@ static void ActorUpdatePosition(TActor *actor, int ticks)
|
||||
actor->MovePos = Vec2iZero();
|
||||
}
|
||||
}
|
||||
static void ActorDie(TActor *actor, const int idx)
|
||||
{
|
||||
// Check if the player has lives to revive
|
||||
if (actor->playerIndex >= 0)
|
||||
{
|
||||
PlayerData *p = CArrayGet(&gPlayerDatas, actor->playerIndex);
|
||||
p->Lives--;
|
||||
CASSERT(p->Lives >= 0, "Player has died too many times");
|
||||
if (p->Lives > 0)
|
||||
{
|
||||
// Find the first player alive; try to spawn next to that position
|
||||
// if no other suitable position exists
|
||||
Vec2i defaultSpawnPosition = Vec2iZero();
|
||||
for (int i = 0; i < (int)gPlayerDatas.size; i++)
|
||||
{
|
||||
const PlayerData *pOther = CArrayGet(&gPlayerDatas, i);
|
||||
if (IsPlayerAlive(pOther))
|
||||
{
|
||||
const TActor *a = CArrayGet(&gActors, pOther->Id);
|
||||
defaultSpawnPosition = a->Pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const Vec2i spawnPos =
|
||||
PlacePlayer(&gMap, p, defaultSpawnPosition, false);
|
||||
|
||||
// Play a spawn sound for players
|
||||
GameEvent sound = GameEventNew(GAME_EVENT_SOUND_AT);
|
||||
// Need to delay it a bit because the camera takes time to update
|
||||
sound.Delay = 1;
|
||||
sound.u.SoundAt.Sound = StrSound("spawn");
|
||||
sound.u.SoundAt.Pos = Vec2iFull2Real(spawnPos);
|
||||
GameEventsEnqueue(&gGameEvents, sound);
|
||||
}
|
||||
}
|
||||
// Add a blood pool
|
||||
AddObjectOld(
|
||||
actor->Pos.x, actor->Pos.y,
|
||||
Vec2iZero(),
|
||||
&cBloodPics[rand() % BLOOD_MAX],
|
||||
OBJ_NONE,
|
||||
TILEITEM_IS_WRECK);
|
||||
ActorDestroy(idx);
|
||||
}
|
||||
|
||||
void ActorsInit(void)
|
||||
{
|
||||
|
@@ -500,8 +500,7 @@ void CommandBadGuys(int ticks)
|
||||
CArrayGet(&gCampaign.Setting.characters.OtherChars, aa.CharId);
|
||||
aa.Health = CharacterGetStartingHealth(c, true);
|
||||
aa.FullPos = PlaceBaddie(&gMap);
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_ADD;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_ADD);
|
||||
e.u.ActorAdd = aa;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
gBaddieCount++;
|
||||
@@ -530,8 +529,7 @@ void InitializeBadGuys(void)
|
||||
CArrayGet(&gCampaign.Setting.characters.OtherChars, aa.CharId);
|
||||
aa.Health = CharacterGetStartingHealth(c, true);
|
||||
aa.FullPos = PlaceBaddie(&gMap);
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_ADD;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_ADD);
|
||||
e.u.ActorAdd = aa;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
|
||||
@@ -560,8 +558,7 @@ void InitializeBadGuys(void)
|
||||
{
|
||||
aa.FullPos = PlaceBaddie(&gMap);
|
||||
}
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_ADD;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_ADD);
|
||||
e.u.ActorAdd = aa;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
|
||||
@@ -595,8 +592,7 @@ void CreateEnemies(void)
|
||||
const Character *c =
|
||||
CArrayGet(&gCampaign.Setting.characters.OtherChars, aa.CharId);
|
||||
aa.Health = CharacterGetStartingHealth(c, true);
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_ADD;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_ADD);
|
||||
e.u.ActorAdd = aa;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
gBaddieCount++;
|
||||
|
@@ -199,8 +199,7 @@ bool UpdateBullet(TMobileObject *obj, const int ticks)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_SOUND_AT;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_SOUND_AT);
|
||||
e.u.SoundAt.Sound = obj->bulletClass->HitSound.Wall;
|
||||
e.u.SoundAt.Pos = realPos;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
@@ -246,8 +245,7 @@ bool UpdateBullet(TMobileObject *obj, const int ticks)
|
||||
MapIsRealPosIn(&gMap, realPos) && ShootWall(realPos.x, realPos.y);
|
||||
if (hitWall && !Vec2iIsZero(obj->vel))
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_SOUND_AT;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_SOUND_AT);
|
||||
e.u.SoundAt.Sound = obj->bulletClass->HitSound.Wall;
|
||||
e.u.SoundAt.Pos = realPos;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
@@ -258,9 +256,7 @@ bool UpdateBullet(TMobileObject *obj, const int ticks)
|
||||
FireGuns(obj, &obj->bulletClass->HitGuns);
|
||||
if (obj->bulletClass->Spark != NULL)
|
||||
{
|
||||
GameEvent e;
|
||||
memset(&e, 0, sizeof e);
|
||||
e.Type = GAME_EVENT_ADD_PARTICLE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ADD_PARTICLE);
|
||||
e.u.AddParticle.Class = obj->bulletClass->Spark;
|
||||
e.u.AddParticle.FullPos = pos;
|
||||
e.u.AddParticle.Z = obj->z;
|
||||
|
@@ -396,7 +396,8 @@ void ConfigLoadDefault(Config *config)
|
||||
config->Game.EnemyDensity = 100;
|
||||
config->Game.FriendlyFire = 0;
|
||||
config->Game.NonPlayerHP = 100;
|
||||
config->Game.PlayerHP = 100;
|
||||
config->Game.PlayerHP = 75;
|
||||
config->Game.Lives = 2;
|
||||
config->Game.RandomSeed = 0;
|
||||
config->Game.SlowMotion = 0;
|
||||
config->Game.Fog = 1;
|
||||
|
@@ -106,6 +106,7 @@ typedef struct
|
||||
int EnemyDensity;
|
||||
int NonPlayerHP;
|
||||
int PlayerHP;
|
||||
int Lives;
|
||||
bool Fog;
|
||||
int SightRange;
|
||||
bool Shadows;
|
||||
|
@@ -55,6 +55,7 @@ static void LoadGameConfigNode(
|
||||
LoadInt(&config->EnemyDensity, node, "EnemyDensity");
|
||||
LoadInt(&config->NonPlayerHP, node, "NonPlayerHP");
|
||||
LoadInt(&config->PlayerHP, node, "PlayerHP");
|
||||
LoadInt(&config->Lives, node, "Lives");
|
||||
LoadBool(&config->Fog, node, "Fog");
|
||||
LoadInt(&config->SightRange, node, "SightRange");
|
||||
LoadBool(&config->Shadows, node, "Shadows");
|
||||
@@ -96,6 +97,7 @@ static void AddGameConfigNode(GameConfig *config, json_t *root)
|
||||
AddIntPair(subConfig, "EnemyDensity", config->EnemyDensity);
|
||||
AddIntPair(subConfig, "NonPlayerHP", config->NonPlayerHP);
|
||||
AddIntPair(subConfig, "PlayerHP", config->PlayerHP);
|
||||
AddIntPair(subConfig, "Lives", config->Lives);
|
||||
json_insert_pair_into_object(
|
||||
subConfig, "Fog", json_new_bool(config->Fog));
|
||||
AddIntPair(subConfig, "SightRange", config->SightRange);
|
||||
|
@@ -553,6 +553,16 @@ static void DrawObjectiveHighlight(
|
||||
}
|
||||
}
|
||||
|
||||
TOffsetPic GetHeadPic(
|
||||
const int bodyType, const direction_e dir, const int face, const int state)
|
||||
{
|
||||
TOffsetPic head;
|
||||
head.dx = cNeckOffset[bodyType][dir].dx + cHeadOffset[face][dir].dx;
|
||||
head.dy = cNeckOffset[bodyType][dir].dy + cHeadOffset[face][dir].dy;
|
||||
head.picIndex = cHeadPic[face][dir][state];
|
||||
return head;
|
||||
}
|
||||
|
||||
void DrawCharacterSimple(
|
||||
const Character *c, const Vec2i pos,
|
||||
const direction_e dir, const int state,
|
||||
@@ -582,13 +592,7 @@ void DrawCharacterSimple(
|
||||
body.dy = cBodyOffset[bodyType][dir].dy;
|
||||
body.picIndex = cBodyPic[bodyType][dir][state];
|
||||
|
||||
head.dx =
|
||||
cNeckOffset[bodyType][headDir].dx +
|
||||
cHeadOffset[c->looks.face][headDir].dx;
|
||||
head.dy =
|
||||
cNeckOffset[bodyType][headDir].dy +
|
||||
cHeadOffset[c->looks.face][headDir].dy;
|
||||
head.picIndex = cHeadPic[c->looks.face][headDir][headState];
|
||||
head = GetHeadPic(bodyType, headDir, c->looks.face, headState);
|
||||
|
||||
gun.picIndex = -1;
|
||||
if (gunPic >= 0)
|
||||
|
@@ -62,5 +62,7 @@ void DrawCharacterSimple(
|
||||
const direction_e dir, const int state,
|
||||
const int gunPic, const gunstate_e gunState,
|
||||
const TranslationTable *table);
|
||||
TOffsetPic GetHeadPic(
|
||||
const int bodyType, const direction_e dir, const int face, const int state);
|
||||
|
||||
#endif
|
||||
|
@@ -69,7 +69,20 @@ void GameEventsEnqueue(CArray *store, GameEvent e)
|
||||
}
|
||||
CArrayPushBack(store, &e);
|
||||
}
|
||||
static bool EventComplete(const void *elem);
|
||||
void GameEventsClear(CArray *store)
|
||||
{
|
||||
CArrayClear(store);
|
||||
CArrayRemoveIf(store, EventComplete);
|
||||
}
|
||||
static bool EventComplete(const void *elem)
|
||||
{
|
||||
return ((GameEvent *)elem)->Delay < 0;
|
||||
}
|
||||
|
||||
GameEvent GameEventNew(GameEventType type)
|
||||
{
|
||||
GameEvent e;
|
||||
memset(&e, 0, sizeof e);
|
||||
e.Type = type;
|
||||
return e;
|
||||
}
|
||||
|
@@ -77,6 +77,7 @@ typedef enum
|
||||
typedef struct
|
||||
{
|
||||
GameEventType Type;
|
||||
int Delay;
|
||||
union
|
||||
{
|
||||
struct
|
||||
@@ -142,4 +143,6 @@ void GameEventsTerminate(CArray *store);
|
||||
void GameEventsEnqueue(CArray *store, GameEvent e);
|
||||
void GameEventsClear(CArray *store);
|
||||
|
||||
GameEvent GameEventNew(GameEventType type);
|
||||
|
||||
#endif
|
||||
|
@@ -62,6 +62,11 @@ static void HandleGameEvent(
|
||||
HealthPickups *hp,
|
||||
EventHandlers *eventHandlers)
|
||||
{
|
||||
e->Delay--;
|
||||
if (e->Delay >= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch (e->Type)
|
||||
{
|
||||
case GAME_EVENT_SCORE:
|
||||
@@ -205,8 +210,7 @@ static void HandleGameEvent(
|
||||
{
|
||||
case OBJECTIVE_COLLECT:
|
||||
{
|
||||
GameEvent e1;
|
||||
e1.Type = GAME_EVENT_SCORE;
|
||||
GameEvent e1 = GameEventNew(GAME_EVENT_SCORE);
|
||||
e1.u.Score.PlayerIndex =
|
||||
e->u.UpdateObjective.PlayerIndex;
|
||||
e1.u.Score.Score = PICKUP_SCORE;
|
||||
@@ -215,8 +219,7 @@ static void HandleGameEvent(
|
||||
break;
|
||||
case OBJECTIVE_DESTROY:
|
||||
{
|
||||
GameEvent e1;
|
||||
e1.Type = GAME_EVENT_SCORE;
|
||||
GameEvent e1 = GameEventNew(GAME_EVENT_SCORE);
|
||||
e1.u.Score.PlayerIndex =
|
||||
e->u.UpdateObjective.PlayerIndex;
|
||||
e1.u.Score.Score = OBJECT_SCORE;
|
||||
|
@@ -54,6 +54,7 @@
|
||||
|
||||
#include "actors.h"
|
||||
#include "automap.h"
|
||||
#include "draw.h"
|
||||
#include "drawtools.h"
|
||||
#include "font.h"
|
||||
#include "game_events.h"
|
||||
@@ -385,6 +386,35 @@ static void DrawHealth(
|
||||
FontStrOpt(s, Vec2iZero(), opts);
|
||||
}
|
||||
|
||||
static void DrawLives(
|
||||
const GraphicsDevice *device, const PlayerData *player, const Vec2i pos,
|
||||
const FontAlign hAlign, const FontAlign vAlign)
|
||||
{
|
||||
const int xStep = hAlign == ALIGN_START ? 10 : -10;
|
||||
const Vec2i offset = Vec2iNew(5, 20);
|
||||
Vec2i drawPos = Vec2iAdd(pos, offset);
|
||||
if (hAlign == ALIGN_END)
|
||||
{
|
||||
const int w = device->cachedConfig.Res.x;
|
||||
drawPos.x = w - drawPos.x - offset.x;
|
||||
}
|
||||
if (vAlign == ALIGN_END)
|
||||
{
|
||||
const int h = device->cachedConfig.Res.y;
|
||||
drawPos.y = h - drawPos.y + offset.y + 5;
|
||||
}
|
||||
const TOffsetPic head = GetHeadPic(
|
||||
BODY_ARMED, DIRECTION_DOWN, player->Char.looks.face, STATE_IDLE);
|
||||
for (int i = 0; i < player->Lives; i++)
|
||||
{
|
||||
BlitOld(
|
||||
drawPos.x + head.dx, drawPos.y + head.dy,
|
||||
PicManagerGetOldPic(&gPicManager, head.picIndex),
|
||||
&player->Char.table, BLIT_TRANSPARENT);
|
||||
drawPos.x += xStep;
|
||||
}
|
||||
}
|
||||
|
||||
#define HUDFLAGS_PLACE_RIGHT 0x01
|
||||
#define HUDFLAGS_PLACE_BOTTOM 0x02
|
||||
#define HUDFLAGS_HALF_SCREEN 0x04
|
||||
@@ -560,15 +590,22 @@ static void DrawPlayerStatus(
|
||||
}
|
||||
if (p)
|
||||
{
|
||||
// Weapon
|
||||
DrawWeaponStatus(
|
||||
device, ActorGetGun(p), pos, opts.HAlign, opts.VAlign);
|
||||
pos.y += rowHeight;
|
||||
|
||||
// Player name
|
||||
opts.Pad = pos;
|
||||
FontStrOpt(s, Vec2iZero(), opts);
|
||||
|
||||
// Health
|
||||
pos.y += rowHeight;
|
||||
DrawHealth(device, p, pos, opts.HAlign, opts.VAlign);
|
||||
|
||||
// Lives
|
||||
pos.y += rowHeight;
|
||||
DrawLives(device, data, pos, opts.HAlign, opts.VAlign);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -845,13 +882,16 @@ void HUDDraw(HUD *hud, int isPaused)
|
||||
|
||||
if (numPlayersAlive == 0)
|
||||
{
|
||||
if (gCampaign.Entry.Mode != CAMPAIGN_MODE_DOGFIGHT)
|
||||
if (AreAllPlayersDeadAndNoLives())
|
||||
{
|
||||
FontStrCenter("Game Over!");
|
||||
}
|
||||
else
|
||||
{
|
||||
FontStrCenter("All Kill!");
|
||||
if (gCampaign.Entry.Mode != CAMPAIGN_MODE_DOGFIGHT)
|
||||
{
|
||||
FontStrCenter("Game Over!");
|
||||
}
|
||||
else
|
||||
{
|
||||
FontStrCenter("All Kill!");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hud->mission->state == MISSION_STATE_PICKUP)
|
||||
|
@@ -111,8 +111,7 @@ void MapStaticLoadDynamic(
|
||||
const Vec2i fullPos = Vec2iReal2Full(Vec2iCenterOfTile(*pos));
|
||||
aa.FullPos.x = fullPos.x;
|
||||
aa.FullPos.y = fullPos.y;
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_ADD;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_ADD);
|
||||
e.u.ActorAdd = aa;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
|
||||
@@ -149,8 +148,7 @@ void MapStaticLoadDynamic(
|
||||
CArrayGet(&gCampaign.Setting.characters.OtherChars, aa.CharId);
|
||||
aa.Health = CharacterGetStartingHealth(c, true);
|
||||
aa.FullPos = fullPosNet;
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_ADD;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_ADD);
|
||||
e.u.ActorAdd = aa;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
@@ -175,8 +173,7 @@ void MapStaticLoadDynamic(
|
||||
CArrayGet(&gCampaign.Setting.characters.OtherChars, aa.CharId);
|
||||
aa.Health = CharacterGetStartingHealth(c, true);
|
||||
aa.FullPos = fullPosNet;
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_ADD;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_ADD);
|
||||
e.u.ActorAdd = aa;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
|
@@ -656,8 +656,7 @@ void MissionSetMessageIfComplete(struct MissionOptions *options)
|
||||
{
|
||||
if (CanCompleteMission(options))
|
||||
{
|
||||
GameEvent msg;
|
||||
msg.Type = GAME_EVENT_MISSION_COMPLETE;
|
||||
GameEvent msg = GameEventNew(GAME_EVENT_MISSION_COMPLETE);
|
||||
GameEventsEnqueue(&gGameEvents, msg);
|
||||
}
|
||||
}
|
||||
@@ -676,8 +675,7 @@ void UpdateMissionObjective(
|
||||
{
|
||||
return;
|
||||
}
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_UPDATE_OBJECTIVE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_UPDATE_OBJECTIVE);
|
||||
e.u.UpdateObjective.ObjectiveIndex = idx;
|
||||
e.u.UpdateObjective.Update = 1;
|
||||
e.u.UpdateObjective.PlayerIndex = player;
|
||||
|
@@ -218,8 +218,7 @@ static void OnReceive(NetClient *n, ENetEvent event)
|
||||
case SERVER_MSG_ACTOR_ADD:
|
||||
{
|
||||
debug(D_VERBOSE, "NetClient: received actor add");
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_ADD;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_ADD);
|
||||
NetDecode(event.packet, &e.u.ActorAdd, NetMsgActorAdd_fields);
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
@@ -227,8 +226,7 @@ static void OnReceive(NetClient *n, ENetEvent event)
|
||||
case SERVER_MSG_ACTOR_MOVE:
|
||||
{
|
||||
debug(D_VERBOSE, "NetClient: received actor move");
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_ACTOR_MOVE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_MOVE);
|
||||
NetDecode(event.packet, &e.u.ActorMove, NetMsgActorMove_fields);
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
|
@@ -226,7 +226,7 @@ static void SendGameStartMessages(
|
||||
NetServer *n, const int peerId, const PlayerData *pData)
|
||||
{
|
||||
// Add the player's actor
|
||||
PlacePlayer(&gMap, pData, Vec2iZero());
|
||||
PlacePlayer(&gMap, pData, Vec2iZero(), true);
|
||||
|
||||
// Send all players
|
||||
for (int i = 0; i < (int)gActors.size; i++)
|
||||
|
@@ -73,6 +73,7 @@ NetMsgPlayerData NetMsgMakePlayerData(const PlayerData *p)
|
||||
{
|
||||
strcpy(d.Weapons[i], p->weapons[i]->name);
|
||||
}
|
||||
d.Lives = p->Lives;
|
||||
d.Score = p->score;
|
||||
d.TotalScore = p->totalScore;
|
||||
d.Kills = p->kills;
|
||||
@@ -104,6 +105,7 @@ void NetMsgPlayerDataUpdate(const NetMsgPlayerData *pd)
|
||||
{
|
||||
p->weapons[i] = StrGunDescription(pd->Weapons[i]);
|
||||
}
|
||||
p->Lives = pd->Lives;
|
||||
p->score = pd->Score;
|
||||
p->totalScore = pd->Score;
|
||||
p->kills = pd->Kills;
|
||||
|
@@ -135,8 +135,7 @@ static void DamageObject(
|
||||
player, pos);
|
||||
if (object->flags & OBJFLAG_QUAKE)
|
||||
{
|
||||
GameEvent shake;
|
||||
shake.Type = GAME_EVENT_SCREEN_SHAKE;
|
||||
GameEvent shake = GameEventNew(GAME_EVENT_SCREEN_SHAKE);
|
||||
shake.u.ShakeAmount = SHAKE_BIG_AMOUNT;
|
||||
GameEventsEnqueue(&gGameEvents, shake);
|
||||
}
|
||||
@@ -175,9 +174,7 @@ static void DamageObject(
|
||||
else
|
||||
{
|
||||
// A wreck left after the destruction of this object
|
||||
GameEvent e;
|
||||
memset(&e, 0, sizeof e);
|
||||
e.Type = GAME_EVENT_ADD_BULLET;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ADD_BULLET);
|
||||
e.u.AddBullet.BulletClass = StrBulletClass("fireball_wreck");
|
||||
e.u.AddBullet.MuzzlePos = fullPos;
|
||||
e.u.AddBullet.MuzzleHeight = 0;
|
||||
@@ -245,8 +242,7 @@ bool DamageSomething(
|
||||
DamageObject(power, flags, player, uid, target);
|
||||
if (gConfig.Sound.Hits && hitSounds != NULL && power > 0)
|
||||
{
|
||||
GameEvent es;
|
||||
es.Type = GAME_EVENT_SOUND_AT;
|
||||
GameEvent es = GameEventNew(GAME_EVENT_SOUND_AT);
|
||||
es.u.SoundAt.Sound = hitSounds->Object;
|
||||
es.u.SoundAt.Pos = pos;
|
||||
GameEventsEnqueue(&gGameEvents, es);
|
||||
@@ -278,8 +274,7 @@ static bool DoDamageCharacter(
|
||||
bool canHit = CanHitCharacter(flags, uid, actor);
|
||||
if (canHit)
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_HIT_CHARACTER;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_HIT_CHARACTER);
|
||||
e.u.HitCharacter.TargetId = actor->tileItem.id;
|
||||
e.u.HitCharacter.Special = special;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
@@ -288,16 +283,14 @@ static bool DoDamageCharacter(
|
||||
(allowFriendlyHitSound || !ActorIsInvulnerable(
|
||||
actor, flags, player, gCampaign.Entry.Mode)))
|
||||
{
|
||||
GameEvent es;
|
||||
es.Type = GAME_EVENT_SOUND_AT;
|
||||
GameEvent es = GameEventNew(GAME_EVENT_SOUND_AT);
|
||||
es.u.SoundAt.Sound = hitSounds->Flesh;
|
||||
es.u.SoundAt.Pos = pos;
|
||||
GameEventsEnqueue(&gGameEvents, es);
|
||||
}
|
||||
if (gConfig.Game.ShotsPushback)
|
||||
{
|
||||
GameEvent ei;
|
||||
ei.Type = GAME_EVENT_ACTOR_IMPULSE;
|
||||
GameEvent ei = GameEventNew(GAME_EVENT_ACTOR_IMPULSE);
|
||||
ei.u.ActorImpulse.Id = actor->tileItem.id;
|
||||
ei.u.ActorImpulse.Vel = Vec2iScaleDiv(
|
||||
Vec2iScale(hitVector, power), SHOT_IMPULSE_DIVISOR);
|
||||
@@ -305,8 +298,7 @@ static bool DoDamageCharacter(
|
||||
}
|
||||
if (CanDamageCharacter(flags, player, uid, actor, special))
|
||||
{
|
||||
GameEvent e1;
|
||||
e1.Type = GAME_EVENT_DAMAGE_CHARACTER;
|
||||
GameEvent e1 = GameEventNew(GAME_EVENT_DAMAGE_CHARACTER);
|
||||
e1.u.DamageCharacter.Power = power;
|
||||
e1.u.DamageCharacter.PlayerIndex = player;
|
||||
e1.u.DamageCharacter.TargetId = actor->tileItem.id;
|
||||
@@ -320,9 +312,7 @@ static bool DoDamageCharacter(
|
||||
|
||||
if (gConfig.Game.Gore != GORE_NONE)
|
||||
{
|
||||
GameEvent eb;
|
||||
memset(&eb, 0, sizeof eb);
|
||||
eb.Type = GAME_EVENT_ADD_PARTICLE;
|
||||
GameEvent eb = GameEventNew(GAME_EVENT_ADD_PARTICLE);
|
||||
eb.u.AddParticle.FullPos = Vec2iReal2Full(pos);
|
||||
eb.u.AddParticle.Z = 10 * Z_FACTOR;
|
||||
int bloodPower = power * 2;
|
||||
@@ -389,8 +379,7 @@ static bool DoDamageCharacter(
|
||||
{
|
||||
// Calculate score based on
|
||||
// if they hit a penalty character
|
||||
GameEvent e2;
|
||||
e2.Type = GAME_EVENT_SCORE;
|
||||
GameEvent e2 = GameEventNew(GAME_EVENT_SCORE);
|
||||
e2.u.Score.PlayerIndex = player;
|
||||
if (actor->flags & FLAGS_PENALTY)
|
||||
{
|
||||
@@ -419,8 +408,7 @@ void UpdateMobileObjects(int ticks)
|
||||
}
|
||||
if ((*(obj->updateFunc))(obj, ticks) == 0)
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_MOBILE_OBJECT_REMOVE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_MOBILE_OBJECT_REMOVE);
|
||||
e.u.MobileObjectRemoveId = i;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
|
@@ -211,8 +211,7 @@ void ParticlesUpdate(CArray *particles, const int ticks)
|
||||
}
|
||||
if (!ParticleUpdate(p, ticks))
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_PARTICLE_REMOVE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_PARTICLE_REMOVE);
|
||||
e.u.ParticleRemoveId = i;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
|
@@ -172,6 +172,8 @@ void PlayerDataTerminate(CArray *p)
|
||||
|
||||
void PlayerDataStart(PlayerData *p, const int maxHealth, const int mission)
|
||||
{
|
||||
p->Lives = gConfig.Game.Lives;
|
||||
|
||||
p->score = 0;
|
||||
p->kills = 0;
|
||||
p->friendlies = 0;
|
||||
@@ -198,6 +200,19 @@ int GetNumPlayers(const bool alive, const bool human, const bool local)
|
||||
return numPlayers;
|
||||
}
|
||||
|
||||
bool AreAllPlayersDeadAndNoLives(void)
|
||||
{
|
||||
for (int i = 0; i < (int)gPlayerDatas.size; i++)
|
||||
{
|
||||
const PlayerData *p = CArrayGet(&gPlayerDatas, i);
|
||||
if (IsPlayerAlive(p) || p->Lives > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const PlayerData *GetFirstPlayer(
|
||||
const bool alive, const bool human, const bool local)
|
||||
{
|
||||
|
@@ -40,6 +40,7 @@ typedef struct
|
||||
char name[20];
|
||||
int weaponCount;
|
||||
const GunDescription *weapons[MAX_WEAPONS];
|
||||
int Lives;
|
||||
|
||||
int score;
|
||||
int totalScore;
|
||||
@@ -71,6 +72,7 @@ void PlayerDataTerminate(CArray *p);
|
||||
void PlayerDataStart(PlayerData *p, const int maxHealth, const int mission);
|
||||
|
||||
int GetNumPlayers(const bool alive, const bool human, const bool local);
|
||||
bool AreAllPlayersDeadAndNoLives(void);
|
||||
const PlayerData *GetFirstPlayer(
|
||||
const bool alive, const bool human, const bool local);
|
||||
bool IsPlayerAlive(const PlayerData *player);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.3.0 at Sat Oct 04 14:39:20 2014. */
|
||||
/* Generated by nanopb-0.3.0 at Wed Nov 12 23:08:53 2014. */
|
||||
|
||||
#include "client.pb.h"
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.3.0 at Sat Oct 04 14:39:20 2014. */
|
||||
/* Generated by nanopb-0.3.0 at Wed Nov 12 23:08:53 2014. */
|
||||
|
||||
#ifndef PB_CLIENT_PB_H_INCLUDED
|
||||
#define PB_CLIENT_PB_H_INCLUDED
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.3.0 at Sat Oct 04 14:39:20 2014. */
|
||||
/* Generated by nanopb-0.3.0 at Wed Nov 12 23:08:53 2014. */
|
||||
|
||||
#include "server.pb.h"
|
||||
|
||||
@@ -21,16 +21,17 @@ const pb_field_t NetMsgCampaignDef_fields[3] = {
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t NetMsgPlayerData_fields[10] = {
|
||||
const pb_field_t NetMsgPlayerData_fields[11] = {
|
||||
PB_FIELD( 1, STRING , REQUIRED, STATIC , FIRST, NetMsgPlayerData, Name, Name, 0),
|
||||
PB_FIELD( 2, MESSAGE , REQUIRED, STATIC , OTHER, NetMsgPlayerData, Looks, Name, &NetMsgPlayerData_CharLooks_fields),
|
||||
PB_FIELD( 3, STRING , REPEATED, STATIC , OTHER, NetMsgPlayerData, Weapons, Looks, 0),
|
||||
PB_FIELD( 4, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, Score, Weapons, 0),
|
||||
PB_FIELD( 5, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, TotalScore, Score, 0),
|
||||
PB_FIELD( 6, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, Kills, TotalScore, 0),
|
||||
PB_FIELD( 7, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, Friendlies, Kills, 0),
|
||||
PB_FIELD( 8, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, PlayerIndex, Friendlies, 0),
|
||||
PB_FIELD( 9, BOOL , REQUIRED, STATIC , OTHER, NetMsgPlayerData, IsUsed, PlayerIndex, 0),
|
||||
PB_FIELD( 4, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, Lives, Weapons, 0),
|
||||
PB_FIELD( 5, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, Score, Lives, 0),
|
||||
PB_FIELD( 6, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, TotalScore, Score, 0),
|
||||
PB_FIELD( 7, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, Kills, TotalScore, 0),
|
||||
PB_FIELD( 8, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, Friendlies, Kills, 0),
|
||||
PB_FIELD( 9, INT32 , REQUIRED, STATIC , OTHER, NetMsgPlayerData, PlayerIndex, Friendlies, 0),
|
||||
PB_FIELD( 10, BOOL , REQUIRED, STATIC , OTHER, NetMsgPlayerData, IsUsed, PlayerIndex, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.3.0 at Sat Oct 04 14:39:20 2014. */
|
||||
/* Generated by nanopb-0.3.0 at Wed Nov 12 23:08:53 2014. */
|
||||
|
||||
#ifndef PB_SERVER_PB_H_INCLUDED
|
||||
#define PB_SERVER_PB_H_INCLUDED
|
||||
@@ -64,6 +64,7 @@ typedef struct _NetMsgPlayerData {
|
||||
NetMsgPlayerData_CharLooks Looks;
|
||||
pb_size_t Weapons_count;
|
||||
char Weapons[3][128];
|
||||
int32_t Lives;
|
||||
int32_t Score;
|
||||
int32_t TotalScore;
|
||||
int32_t Kills;
|
||||
@@ -78,7 +79,7 @@ extern const int32_t NetMsgActorAdd_PlayerId_default;
|
||||
/* Initializer values for message structs */
|
||||
#define NetMsgClientId_init_default {0}
|
||||
#define NetMsgCampaignDef_init_default {"", 0}
|
||||
#define NetMsgPlayerData_init_default {"", NetMsgPlayerData_CharLooks_init_default, 0, {"", "", ""}, 0, 0, 0, 0, 0, 0}
|
||||
#define NetMsgPlayerData_init_default {"", NetMsgPlayerData_CharLooks_init_default, 0, {"", "", ""}, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define NetMsgPlayerData_CharLooks_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define NetMsgAddPlayers_init_default {0, 0, {0, 0, 0, 0}}
|
||||
#define NetMsgVec2i_init_default {0, 0}
|
||||
@@ -86,7 +87,7 @@ extern const int32_t NetMsgActorAdd_PlayerId_default;
|
||||
#define NetMsgActorMove_init_default {0, NetMsgVec2i_init_default}
|
||||
#define NetMsgClientId_init_zero {0}
|
||||
#define NetMsgCampaignDef_init_zero {"", 0}
|
||||
#define NetMsgPlayerData_init_zero {"", NetMsgPlayerData_CharLooks_init_zero, 0, {"", "", ""}, 0, 0, 0, 0, 0, 0}
|
||||
#define NetMsgPlayerData_init_zero {"", NetMsgPlayerData_CharLooks_init_zero, 0, {"", "", ""}, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define NetMsgPlayerData_CharLooks_init_zero {0, 0, 0, 0, 0, 0}
|
||||
#define NetMsgAddPlayers_init_zero {0, 0, {0, 0, 0, 0}}
|
||||
#define NetMsgVec2i_init_zero {0, 0}
|
||||
@@ -119,17 +120,18 @@ extern const int32_t NetMsgActorAdd_PlayerId_default;
|
||||
#define NetMsgPlayerData_Name_tag 1
|
||||
#define NetMsgPlayerData_Looks_tag 2
|
||||
#define NetMsgPlayerData_Weapons_tag 3
|
||||
#define NetMsgPlayerData_Score_tag 4
|
||||
#define NetMsgPlayerData_TotalScore_tag 5
|
||||
#define NetMsgPlayerData_Kills_tag 6
|
||||
#define NetMsgPlayerData_Friendlies_tag 7
|
||||
#define NetMsgPlayerData_PlayerIndex_tag 8
|
||||
#define NetMsgPlayerData_IsUsed_tag 9
|
||||
#define NetMsgPlayerData_Lives_tag 4
|
||||
#define NetMsgPlayerData_Score_tag 5
|
||||
#define NetMsgPlayerData_TotalScore_tag 6
|
||||
#define NetMsgPlayerData_Kills_tag 7
|
||||
#define NetMsgPlayerData_Friendlies_tag 8
|
||||
#define NetMsgPlayerData_PlayerIndex_tag 9
|
||||
#define NetMsgPlayerData_IsUsed_tag 10
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
extern const pb_field_t NetMsgClientId_fields[2];
|
||||
extern const pb_field_t NetMsgCampaignDef_fields[3];
|
||||
extern const pb_field_t NetMsgPlayerData_fields[10];
|
||||
extern const pb_field_t NetMsgPlayerData_fields[11];
|
||||
extern const pb_field_t NetMsgPlayerData_CharLooks_fields[7];
|
||||
extern const pb_field_t NetMsgAddPlayers_fields[3];
|
||||
extern const pb_field_t NetMsgVec2i_fields[3];
|
||||
@@ -139,7 +141,7 @@ extern const pb_field_t NetMsgActorMove_fields[3];
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define NetMsgClientId_size 11
|
||||
#define NetMsgCampaignDef_size 4105
|
||||
#define NetMsgPlayerData_size 540
|
||||
#define NetMsgPlayerData_size 551
|
||||
#define NetMsgPlayerData_CharLooks_size 66
|
||||
#define NetMsgAddPlayers_size 55
|
||||
#define NetMsgVec2i_size 22
|
||||
|
@@ -19,12 +19,13 @@ message NetMsgPlayerData {
|
||||
}
|
||||
required CharLooks Looks = 2;
|
||||
repeated string Weapons = 3;
|
||||
required int32 Score = 4;
|
||||
required int32 TotalScore = 5;
|
||||
required int32 Kills = 6;
|
||||
required int32 Friendlies = 7;
|
||||
required int32 PlayerIndex = 8;
|
||||
required bool IsUsed = 9;
|
||||
required int32 Lives = 4;
|
||||
required int32 Score = 5;
|
||||
required int32 TotalScore = 6;
|
||||
required int32 Kills = 7;
|
||||
required int32 Friendlies = 8;
|
||||
required int32 PlayerIndex = 9;
|
||||
required bool IsUsed = 10;
|
||||
}
|
||||
|
||||
message NetMsgAddPlayers {
|
||||
|
@@ -432,9 +432,7 @@ void GunAddBullets(
|
||||
((double)rand() / RAND_MAX * g->Recoil) - g->Recoil / 2;
|
||||
const double finalAngle =
|
||||
radians + spreadStartAngle + i * g->Spread.Width + recoil;
|
||||
GameEvent e;
|
||||
memset(&e, 0, sizeof e);
|
||||
e.Type = GAME_EVENT_ADD_BULLET;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ADD_BULLET);
|
||||
e.u.AddBullet.BulletClass = g->Bullet;
|
||||
e.u.AddBullet.MuzzlePos = fullPos;
|
||||
e.u.AddBullet.MuzzleHeight = z;
|
||||
@@ -461,8 +459,7 @@ void GunAddBullets(
|
||||
}
|
||||
if (g->ShakeAmount > 0)
|
||||
{
|
||||
GameEvent shake;
|
||||
shake.Type = GAME_EVENT_SCREEN_SHAKE;
|
||||
GameEvent shake = GameEventNew(GAME_EVENT_SCREEN_SHAKE);
|
||||
shake.u.ShakeAmount = g->ShakeAmount;
|
||||
GameEventsEnqueue(&gGameEvents, shake);
|
||||
}
|
||||
@@ -472,9 +469,7 @@ static void AddBrass(
|
||||
const GunDescription *g, const direction_e d, const Vec2i pos)
|
||||
{
|
||||
CASSERT(g->Brass, "Cannot create brass for no-brass weapon");
|
||||
GameEvent e;
|
||||
memset(&e, 0, sizeof e);
|
||||
e.Type = GAME_EVENT_ADD_PARTICLE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_ADD_PARTICLE);
|
||||
e.u.AddParticle.Class = g->Brass;
|
||||
double x, y;
|
||||
const double radians = dir2radians[d];
|
||||
|
29
src/game.c
29
src/game.c
@@ -409,8 +409,7 @@ bool RunGame(struct MissionOptions *m, Map *map)
|
||||
crosshair->offset.y = -crosshair->size.y / 2;
|
||||
EventReset(&gEventHandlers, crosshair);
|
||||
|
||||
GameEvent start;
|
||||
start.Type = GAME_EVENT_GAME_START;
|
||||
GameEvent start = GameEventNew(GAME_EVENT_GAME_START);
|
||||
GameEventsEnqueue(&gGameEvents, start);
|
||||
|
||||
// Set mission complete and display exit if it is complete
|
||||
@@ -437,8 +436,7 @@ static void RunGameInput(void *data)
|
||||
|
||||
if (gEventHandlers.HasQuit)
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_MISSION_END;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_MISSION_END);
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
return;
|
||||
}
|
||||
@@ -482,8 +480,7 @@ static void RunGameInput(void *data)
|
||||
if (rData->isPaused)
|
||||
{
|
||||
// Exit
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_MISSION_END;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_MISSION_END);
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
// Need to unpause to process the quit
|
||||
rData->isPaused = false;
|
||||
@@ -564,8 +561,7 @@ static GameLoopResult RunGameUpdate(void *data)
|
||||
}
|
||||
const TActor *p = CArrayGet(&gActors, pd->Id);
|
||||
const int pad = SPLIT_PADDING;
|
||||
GameEvent ei;
|
||||
ei.Type = GAME_EVENT_ACTOR_IMPULSE;
|
||||
GameEvent ei = GameEventNew(GAME_EVENT_ACTOR_IMPULSE);
|
||||
ei.u.ActorImpulse.Id = p->tileItem.id;
|
||||
ei.u.ActorImpulse.Vel = p->Vel;
|
||||
if (screen.x + pad > p->tileItem.x && p->Vel.x < 256)
|
||||
@@ -626,21 +622,18 @@ static void CheckMissionCompletion(const struct MissionOptions *mo)
|
||||
GetNumPlayers(true, false, false) > 0 && IsMissionComplete(mo);
|
||||
if (mo->state == MISSION_STATE_PLAY && isMissionComplete)
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_MISSION_PICKUP;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_MISSION_PICKUP);
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
if (mo->state == MISSION_STATE_PICKUP && !isMissionComplete)
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_MISSION_INCOMPLETE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_MISSION_INCOMPLETE);
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
if (mo->state == MISSION_STATE_PICKUP &&
|
||||
mo->pickupTime + PICKUP_LIMIT <= mo->time)
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_MISSION_END;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_MISSION_END);
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
|
||||
@@ -657,10 +650,9 @@ static void CheckMissionCompletion(const struct MissionOptions *mo)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allPlayersDestroyed)
|
||||
if (allPlayersDestroyed && AreAllPlayersDeadAndNoLives())
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_MISSION_END;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_MISSION_END);
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
}
|
||||
}
|
||||
@@ -696,8 +688,7 @@ static void MissionUpdateObjectives(struct MissionOptions *mo, Map *map)
|
||||
int update = MapGetExploredPercentage(map) - o->done;
|
||||
if (update > 0)
|
||||
{
|
||||
GameEvent e;
|
||||
e.Type = GAME_EVENT_UPDATE_OBJECTIVE;
|
||||
GameEvent e = GameEventNew(GAME_EVENT_UPDATE_OBJECTIVE);
|
||||
e.u.UpdateObjective.ObjectiveIndex = i;
|
||||
e.u.UpdateObjective.Update = update;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
|
@@ -326,6 +326,13 @@ menu_t *MenuCreateOptionsGame(const char *name, MenuSystem *ms)
|
||||
&gConfig.Game.PlayerHP,
|
||||
25, 200, 25,
|
||||
MENU_OPTION_DISPLAY_STYLE_INT_TO_STR_FUNC, (void (*)(void))PercentStr));
|
||||
MenuAddSubmenu(
|
||||
menu,
|
||||
MenuCreateOptionRange(
|
||||
"Lives",
|
||||
&gConfig.Game.Lives,
|
||||
0, 5, 1,
|
||||
MENU_OPTION_DISPLAY_STYLE_INT, NULL));
|
||||
MenuAddSubmenu(
|
||||
menu,
|
||||
MenuCreateOptionToggle(
|
||||
|
Reference in New Issue
Block a user