mirror of
https://github.com/cxong/cdogs-sdl.git
synced 2025-07-23 07:23:01 +02:00
Add door close delay (fixes #206)
This commit is contained in:
BIN
sounds/door_close.ogg
Normal file
BIN
sounds/door_close.ogg
Normal file
Binary file not shown.
3
sounds/door_close.txt
Normal file
3
sounds/door_close.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Derived from Slide by jberkuta14
|
||||
https://www.freesound.org/people/jberkuta14/sounds/134894/
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
@@ -194,6 +194,8 @@ static void PicLoadOffset(Pic *picAlt, const int idx)
|
||||
picAlt->Data = oldPic->Data;
|
||||
picAlt->offset = Vec2iNew(cGeneralPics[idx].dx, cGeneralPics[idx].dy);
|
||||
}
|
||||
// 1 second to close doors
|
||||
#define CLOSE_DOOR_TICKS FPS_FRAMELIMIT
|
||||
// Create the watch responsible for closing the door
|
||||
static TWatch *CreateCloseDoorWatch(
|
||||
Map *map, const Mission *m, const Vec2i v,
|
||||
@@ -208,19 +210,13 @@ static TWatch *CreateCloseDoorWatch(
|
||||
for (int i = 0; i < doorGroupCount; i++)
|
||||
{
|
||||
const Vec2i vI = Vec2iAdd(v, Vec2iScale(dv, i));
|
||||
Condition *c;
|
||||
|
||||
c = WatchAddCondition(w);
|
||||
c->condition = CONDITION_TILECLEAR;
|
||||
c->pos = Vec2iNew(vI.x - dAside.x, vI.y - dAside.y);
|
||||
|
||||
c = WatchAddCondition(w);
|
||||
c->condition = CONDITION_TILECLEAR;
|
||||
c->pos = vI;
|
||||
|
||||
c = WatchAddCondition(w);
|
||||
c->condition = CONDITION_TILECLEAR;
|
||||
c->pos = Vec2iNew(vI.x + dAside.x, vI.y + dAside.y);
|
||||
WatchAddCondition(
|
||||
w, CONDITION_TILECLEAR, CLOSE_DOOR_TICKS, Vec2iMinus(vI, dAside));
|
||||
WatchAddCondition(
|
||||
w, CONDITION_TILECLEAR, CLOSE_DOOR_TICKS, vI);
|
||||
WatchAddCondition(
|
||||
w, CONDITION_TILECLEAR, CLOSE_DOOR_TICKS, Vec2iAdd(vI, dAside));
|
||||
}
|
||||
|
||||
// Now the actions of the watch once it's triggered
|
||||
@@ -230,12 +226,12 @@ static TWatch *CreateCloseDoorWatch(
|
||||
a = WatchAddAction(w);
|
||||
a->Type = ACTION_DEACTIVATEWATCH;
|
||||
a->u.index = w->index;
|
||||
// play sound at the center of the door group
|
||||
// play close sound at the center of the door group
|
||||
a = WatchAddAction(w);
|
||||
a->Type = ACTION_SOUND;
|
||||
a->u.pos = Vec2iCenterOfTile(
|
||||
Vec2iAdd(v, Vec2iScale(dv, doorGroupCount / 2)));
|
||||
a->a.Sound = StrSound("door");
|
||||
a->a.Sound = StrSound("door_close");
|
||||
|
||||
// Close doors
|
||||
for (int i = 0; i < doorGroupCount; i++)
|
||||
|
@@ -47,6 +47,7 @@ void GrafxMakeRandomBackground(
|
||||
ObjsInit();
|
||||
MobObjsInit();
|
||||
PickupsInit();
|
||||
WatchesInit();
|
||||
SetupQuickPlayCampaign(&co->Setting);
|
||||
co->seed = rand();
|
||||
tint.h = rand() * 360.0 / RAND_MAX;
|
||||
@@ -62,7 +63,7 @@ void GrafxMakeRandomBackground(
|
||||
ObjsTerminate();
|
||||
MobObjsTerminate();
|
||||
PickupsTerminate();
|
||||
RemoveAllWatches();
|
||||
WatchesTerminate();
|
||||
MissionOptionsTerminate(mo);
|
||||
CampaignSettingTerminate(&co->Setting);
|
||||
co->seed = ConfigGetInt(&gConfig, "Game.RandomSeed");
|
||||
|
@@ -470,15 +470,10 @@ void SetupMission(
|
||||
MobObjsInit();
|
||||
PickupsInit();
|
||||
ParticlesInit(&gParticles);
|
||||
WatchesInit();
|
||||
SetupObjectives(mo, m);
|
||||
SetupBadguysForMission(m);
|
||||
SetupWeapons(&mo->Weapons, &m->Weapons);
|
||||
// TODO: store colours instead and request during map load
|
||||
/*RecolourPics(
|
||||
abs(m->WallColor) % COLORRANGE_COUNT,
|
||||
abs(m->FloorColor) % COLORRANGE_COUNT,
|
||||
abs(m->RoomColor) % COLORRANGE_COUNT,
|
||||
abs(m->AltColor) % COLORRANGE_COUNT);*/
|
||||
if (buildTables)
|
||||
{
|
||||
BuildTranslationTables(gPicManager.palette);
|
||||
@@ -492,7 +487,7 @@ void MissionEnd(void)
|
||||
MobObjsTerminate();
|
||||
PickupsTerminate();
|
||||
ParticlesTerminate(&gParticles);
|
||||
RemoveAllWatches();
|
||||
WatchesTerminate();
|
||||
for (int i = 0; i < (int)gPlayerDatas.size; i++)
|
||||
{
|
||||
PlayerData *p = CArrayGet(&gPlayerDatas, i);
|
||||
|
@@ -55,8 +55,7 @@
|
||||
#include "sounds.h"
|
||||
#include "utils.h"
|
||||
|
||||
static TWatch *activeWatches = NULL;
|
||||
static TWatch *inactiveWatches = NULL;
|
||||
CArray gWatches; // of TWatch
|
||||
static int watchIndex = 1;
|
||||
|
||||
|
||||
@@ -83,19 +82,24 @@ Action *TriggerAddAction(Trigger *t)
|
||||
|
||||
TWatch *WatchNew(void)
|
||||
{
|
||||
TWatch *t;
|
||||
CCALLOC(t, sizeof(TWatch));
|
||||
t->index = watchIndex++;
|
||||
t->next = inactiveWatches;
|
||||
inactiveWatches = t;
|
||||
CArrayInit(&t->actions, sizeof(Action));
|
||||
CArrayInit(&t->conditions, sizeof(Condition));
|
||||
return t;
|
||||
TWatch t;
|
||||
memset(&t, 0, sizeof(TWatch));
|
||||
t.index = watchIndex++;
|
||||
CArrayInit(&t.actions, sizeof(Action));
|
||||
CArrayInit(&t.conditions, sizeof(Condition));
|
||||
t.active = false;
|
||||
CArrayPushBack(&gWatches, &t);
|
||||
return CArrayGet(&gWatches, gWatches.size - 1);
|
||||
}
|
||||
Condition *WatchAddCondition(TWatch *w)
|
||||
Condition *WatchAddCondition(
|
||||
TWatch *w, const ConditionType type, const int counterMax,
|
||||
const Vec2i pos)
|
||||
{
|
||||
Condition c;
|
||||
memset(&c, 0, sizeof c);
|
||||
c.Type = type;
|
||||
c.CounterMax = counterMax;
|
||||
c.Pos = pos;
|
||||
CArrayPushBack(&w->conditions, &c);
|
||||
return CArrayGet(&w->conditions, w->conditions.size - 1);
|
||||
}
|
||||
@@ -109,58 +113,52 @@ Action *WatchAddAction(TWatch *w)
|
||||
|
||||
static void ActivateWatch(int idx)
|
||||
{
|
||||
TWatch **h = &inactiveWatches;
|
||||
TWatch *t;
|
||||
for (int i = 0; i < (int)gWatches.size; i++)
|
||||
{
|
||||
TWatch *w = CArrayGet(&gWatches, i);
|
||||
if (w->index == idx)
|
||||
{
|
||||
w->active = true;
|
||||
|
||||
while (*h && (*h)->index != idx)
|
||||
{
|
||||
h = &((*h)->next);
|
||||
}
|
||||
if (*h)
|
||||
{
|
||||
t = *h;
|
||||
*h = t->next;
|
||||
t->next = activeWatches;
|
||||
activeWatches = t;
|
||||
// Reset all conditions related to watch
|
||||
for (int j = 0; j < (int)w->conditions.size; j++)
|
||||
{
|
||||
Condition *c = CArrayGet(&w->conditions, j);
|
||||
c->Counter = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
CASSERT(false, "Cannot find watch");
|
||||
}
|
||||
|
||||
static void DeactivateWatch(int idx)
|
||||
{
|
||||
TWatch **h = &activeWatches;
|
||||
TWatch *t;
|
||||
|
||||
while (*h && (*h)->index != idx)
|
||||
for (int i = 0; i < (int)gWatches.size; i++)
|
||||
{
|
||||
h = &((*h)->next);
|
||||
}
|
||||
if (*h)
|
||||
{
|
||||
t = *h;
|
||||
*h = t->next;
|
||||
t->next = inactiveWatches;
|
||||
inactiveWatches = t;
|
||||
TWatch *w = CArrayGet(&gWatches, i);
|
||||
if (w->index == idx)
|
||||
{
|
||||
w->active = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CASSERT(false, "Cannot find watch");
|
||||
}
|
||||
|
||||
void RemoveAllWatches(void)
|
||||
void WatchesInit(void)
|
||||
{
|
||||
TWatch *t;
|
||||
|
||||
while (activeWatches) {
|
||||
t = activeWatches;
|
||||
activeWatches = t->next;
|
||||
CArrayTerminate(&t->conditions);
|
||||
CArrayTerminate(&t->actions);
|
||||
CFREE(t);
|
||||
}
|
||||
while (inactiveWatches) {
|
||||
t = inactiveWatches;
|
||||
inactiveWatches = t->next;
|
||||
CArrayTerminate(&t->conditions);
|
||||
CArrayTerminate(&t->actions);
|
||||
CFREE(t);
|
||||
CArrayInit(&gWatches, sizeof(TWatch));
|
||||
}
|
||||
void WatchesTerminate(void)
|
||||
{
|
||||
for (int i = 0; i < (int)gWatches.size; i++)
|
||||
{
|
||||
TWatch *w = CArrayGet(&gWatches, i);
|
||||
CArrayTerminate(&w->conditions);
|
||||
CArrayTerminate(&w->actions);
|
||||
}
|
||||
CArrayTerminate(&gWatches);
|
||||
}
|
||||
|
||||
static void ActionRun(Action *a, CArray *mapTriggers)
|
||||
@@ -217,23 +215,32 @@ static void ActionRun(Action *a, CArray *mapTriggers)
|
||||
}
|
||||
}
|
||||
|
||||
static int ConditionsMet(CArray *conditions)
|
||||
static bool ConditionsMet(CArray *conditions, const int ticks)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (int)conditions->size; i++)
|
||||
bool allConditionsMet = true;
|
||||
for (int i = 0; i < (int)conditions->size; i++)
|
||||
{
|
||||
Condition *c = CArrayGet(conditions, i);
|
||||
switch (c->condition)
|
||||
bool conditionMet = false;
|
||||
switch (c->Type)
|
||||
{
|
||||
case CONDITION_TILECLEAR:
|
||||
if (!TileIsClear(MapGetTile(&gMap, c->pos)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
conditionMet = TileIsClear(MapGetTile(&gMap, c->Pos));
|
||||
break;
|
||||
}
|
||||
if (conditionMet)
|
||||
{
|
||||
c->Counter += ticks;
|
||||
allConditionsMet =
|
||||
allConditionsMet && c->Counter >= c->CounterMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Counter = 0;
|
||||
allConditionsMet = false;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return allConditionsMet;
|
||||
}
|
||||
|
||||
bool TriggerCanActivate(const Trigger *t, const int flags)
|
||||
@@ -249,20 +256,17 @@ void TriggerActivate(Trigger *t, CArray *mapTriggers)
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateWatches(CArray *mapTriggers)
|
||||
void UpdateWatches(CArray *mapTriggers, const int ticks)
|
||||
{
|
||||
TWatch *a = activeWatches;
|
||||
TWatch *current;
|
||||
|
||||
while (a) {
|
||||
current = a;
|
||||
a = a->next;
|
||||
if (ConditionsMet(¤t->conditions))
|
||||
for (int i = 0; i < (int)gWatches.size; i++)
|
||||
{
|
||||
TWatch *w = CArrayGet(&gWatches, i);
|
||||
if (!w->active) continue;
|
||||
if (ConditionsMet(&w->conditions, ticks))
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (int)current->actions.size; i++)
|
||||
for (int j = 0; j < (int)w->actions.size; j++)
|
||||
{
|
||||
ActionRun(CArrayGet(¤t->actions, i), mapTriggers);
|
||||
ActionRun(CArrayGet(&w->actions, j), mapTriggers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -64,8 +64,6 @@ typedef enum
|
||||
ACTION_SOUND
|
||||
} ActionType;
|
||||
|
||||
#define CONDITION_TILECLEAR 1
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -97,29 +95,42 @@ typedef struct
|
||||
} Trigger;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CONDITION_TILECLEAR = 1
|
||||
} ConditionType;
|
||||
typedef struct
|
||||
{
|
||||
int condition;
|
||||
Vec2i pos;
|
||||
ConditionType Type;
|
||||
// How many ticks has this condition been fulfilled
|
||||
// Reset to 0 when condition failed
|
||||
int Counter;
|
||||
int CounterMax;
|
||||
Vec2i Pos;
|
||||
} Condition;
|
||||
|
||||
|
||||
struct Watch {
|
||||
typedef struct
|
||||
{
|
||||
int index;
|
||||
CArray conditions; // of Condition
|
||||
CArray actions; // of Action
|
||||
struct Watch *next;
|
||||
};
|
||||
typedef struct Watch TWatch;
|
||||
bool active;
|
||||
} TWatch;
|
||||
|
||||
|
||||
bool TriggerCanActivate(const Trigger *t, const int flags);
|
||||
void TriggerActivate(Trigger *t, CArray *mapTriggers);
|
||||
void UpdateWatches(CArray *mapTriggers);
|
||||
void UpdateWatches(CArray *mapTriggers, const int ticks);
|
||||
Trigger *TriggerNew(void);
|
||||
void TriggerTerminate(Trigger *t);
|
||||
Action *TriggerAddAction(Trigger *t);
|
||||
|
||||
void WatchesInit(void);
|
||||
void WatchesTerminate(void);
|
||||
|
||||
TWatch *WatchNew(void);
|
||||
Condition *WatchAddCondition(TWatch *w);
|
||||
Condition *WatchAddCondition(
|
||||
TWatch *w, const ConditionType type, const int counterMax,
|
||||
const Vec2i pos);
|
||||
Action *WatchAddAction(TWatch *w);
|
||||
void RemoveAllWatches(void);
|
||||
|
@@ -610,7 +610,7 @@ static GameLoopResult RunGameUpdate(void *data)
|
||||
UpdateMobileObjects(ticksPerFrame);
|
||||
ParticlesUpdate(&gParticles, ticksPerFrame);
|
||||
|
||||
UpdateWatches(&rData->map->triggers);
|
||||
UpdateWatches(&rData->map->triggers, ticksPerFrame);
|
||||
|
||||
PowerupSpawnerUpdate(&rData->healthSpawner, ticksPerFrame);
|
||||
for (int i = 0; i < (int)rData->ammoSpawners.size; i++)
|
||||
|
Reference in New Issue
Block a user