Skip to content

Commit

Permalink
Add basic item spawners (#329)
Browse files Browse the repository at this point in the history
Add spawn item tech demo level
Fix bug where items sometimes cannot be picked up if
other things exist inside the same tile
Add item spawn sound for ammo and health
Fix bug where map items cannot be placed on drain tile
Fix potential indexing bug with wrecks
  • Loading branch information
cxong committed Feb 23, 2015
1 parent 4b37e33 commit 228468b
Show file tree
Hide file tree
Showing 21 changed files with 381 additions and 58 deletions.
Binary file added graphics/spawn_pad.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions graphics/spawn_pad.txt
@@ -0,0 +1,4 @@
Adapted from Sci-Fi Object Set by Janna
http://opengameart.org/content/sci-fi-object-set

http://creativecommons.org/publicdomain/zero/1.0/
7 changes: 7 additions & 0 deletions missions/techdemo/spawnertest.cdogscpn/campaign.json
@@ -0,0 +1,7 @@
{
"Version": 4,
"Title": "Spawner Test",
"Author": "Cong",
"Description": "Testing some spawners",
"Missions": 1
}
3 changes: 3 additions & 0 deletions missions/techdemo/spawnertest.cdogscpn/characters.json
@@ -0,0 +1,3 @@
{
"Characters": []
}
101 changes: 101 additions & 0 deletions missions/techdemo/spawnertest.cdogscpn/missions.json
@@ -0,0 +1,101 @@
{
"Missions": [{
"Title": "",
"Description": "",
"Type": "Static",
"Width": 16,
"Height": 16,
"WallStyle": 2,
"FloorStyle": 9,
"RoomStyle": 9,
"ExitStyle": 1,
"KeyStyle": 0,
"DoorStyle": 0,
"Objectives": [],
"Enemies": [],
"SpecialChars": [],
"MapObjectDensities": [],
"EnemyDensity": 0,
"Weapons": ["Knife",
"Machine gun",
"Grenades",
"Flamer",
"Shotgun",
"Powergun",
"Shrapnel bombs",
"Molotovs",
"Sniper rifle",
"Prox. mine",
"Dynamite",
"Chemo bombs",
"Petrify gun",
"Browny gun",
"Confusion bombs",
"Chemo gun",
"Pulse rifle",
"Heatseeker",
"Swarmer",
"Launcher",
"Pistol"],
"Song": "",
"WallColor": 8,
"FloorColor": 12,
"RoomColor": 8,
"AltColor": 9,
"Tiles": "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",
"StaticItems": [{
"MapObject": "Bullets spawner",
"Positions": [[2,
2]]
},
{
"MapObject": "Grenades spawner",
"Positions": [[4,
2]]
},
{
"MapObject": "Gas tank spawner",
"Positions": [[6,
2]]
},
{
"MapObject": "Shells spawner",
"Positions": [[8,
2]]
},
{
"MapObject": "Cells spawner",
"Positions": [[10,
2]]
},
{
"MapObject": "Frag grenades spawner",
"Positions": [[12,
2]]
},
{
"MapObject": "Molotovs spawner",
"Positions": [[2,
4]]
},
{
"MapObject": "Mines spawner",
"Positions": [[4,
4],
[10,
4]]
}],
"StaticWrecks": [],
"StaticCharacters": [],
"StaticObjectives": [],
"StaticKeys": [],
"Start": [0,
0],
"Exit": {
"Start": [0,
0],
"End": [0,
0]
}
}]
}
Binary file added sounds/spawn_item.ogg
Binary file not shown.
3 changes: 3 additions & 0 deletions sounds/spawn_item.txt
@@ -0,0 +1,3 @@
alien_phaser.R.wav by torn.rugged.audio.35
http://freesound.org/people/torn.rugged.audio.35/sounds/45935/
http://creativecommons.org/publicdomain/zero/1.0/
34 changes: 23 additions & 11 deletions src/cdogs/actors.c
Expand Up @@ -353,6 +353,7 @@ static void CheckTrigger(const Vec2i tilePos)
static Vec2i GetConstrainedFullPos(
const Map *map, const Vec2i fromFull, const Vec2i toFull,
const Vec2i size);
static void CheckPickups(TActor *actor, const Vec2i realPos);
bool TryMoveActor(TActor *actor, Vec2i pos)
{
CASSERT(!Vec2iEqual(actor->Pos, pos), "trying to move to same position");
Expand Down Expand Up @@ -457,17 +458,7 @@ bool TryMoveActor(TActor *actor, Vec2i pos)

CheckTrigger(Vec2iToTile(realPos));

if (actor->playerIndex >= 0)
{
target = GetItemOnTileInCollision(
&actor->tileItem, realPos, 0,
CalcCollisionTeam(1, actor),
IsPVP(gCampaign.Entry.Mode));
if (target && target->kind == KIND_PICKUP)
{
PickupPickup(actor, CArrayGet(&gPickups, target->id));
}
}
CheckPickups(actor, realPos);

GameEvent e = GameEventNew(GAME_EVENT_ACTOR_MOVE);
e.u.ActorMove.Id = actor->tileItem.id;
Expand Down Expand Up @@ -573,6 +564,27 @@ static Vec2i GetConstrainedFullPos(
// All alternative movements are in collision; don't move
return fromFull;
}
// Check if the player can pickup any item
static void CheckPickupFunc(TTileItem *ti, void *data);
static void CheckPickups(TActor *actor, const Vec2i realPos)
{
// NPCs can't pickup
if (actor->playerIndex < 0)
{
return;
}
CollideAllItems(
&actor->tileItem, realPos, 0, CalcCollisionTeam(true, actor),
IsPVP(gCampaign.Entry.Mode), CheckPickupFunc, actor);
}
static void CheckPickupFunc(TTileItem *ti, void *data)
{
TActor *actor = data;
if (ti->kind == KIND_PICKUP)
{
PickupPickup(actor, CArrayGet(&gPickups, ti->id));
}
}

void ActorHeal(TActor *actor, int health)
{
Expand Down
3 changes: 2 additions & 1 deletion src/cdogs/collision.c
Expand Up @@ -223,6 +223,7 @@ bool CollisionIsOnSameTeam(
!isPVP;
}

// TODO: refactor away into CollideAllItems, use bool continue on callback
TTileItem *GetItemOnTileInCollision(
const TTileItem *item, Vec2i pos, int mask, CollisionTeam team,
const bool isPVP)
Expand Down Expand Up @@ -284,7 +285,7 @@ void CollideAllItems(
if (!CollisionIsOnSameTeam(ti, team, isPVP))
{
if (item != ti &&
(ti->flags & mask) &&
(mask == 0 || (ti->flags & mask)) &&
ItemsCollide(item, ti, pos))
{
func(ti, data);
Expand Down
76 changes: 47 additions & 29 deletions src/cdogs/handle_game_events.c
Expand Up @@ -128,7 +128,16 @@ static void HandleGameEvent(
}
break;
case GAME_EVENT_ADD_HEALTH_PICKUP:
MapPlaceHealth(e->u.AddHealthPickup);
{
MapPlaceHealth(e->u.AddHealthPickup);
// Play a spawn sound
GameEvent sound = GameEventNew(GAME_EVENT_SOUND_AT);
sound.u.SoundAt.Sound = StrSound("spawn_item");
sound.u.SoundAt.Pos = e->u.AddHealthPickup.Pos;
HandleGameEvent(
&sound, hud, shake, healthSpawner, ammoSpawners,
eventHandlers);
}
break;
case GAME_EVENT_TAKE_HEALTH_PICKUP:
{
Expand All @@ -152,45 +161,54 @@ static void HandleGameEvent(
}
break;
case GAME_EVENT_ADD_AMMO_PICKUP:
MapPlaceAmmo(e->u.AddAmmoPickup);
{
MapPlaceAmmo(e->u.AddAmmoPickup);
// Play a spawn sound
GameEvent sound = GameEventNew(GAME_EVENT_SOUND_AT);
sound.u.SoundAt.Sound = StrSound("spawn_item");
sound.u.SoundAt.Pos = e->u.AddAmmoPickup.Pos;
HandleGameEvent(
&sound, hud, shake, healthSpawner, ammoSpawners,
eventHandlers);
}
break;
case GAME_EVENT_TAKE_AMMO_PICKUP:
{
const PlayerData *p =
CArrayGet(&gPlayerDatas, e->u.Heal.PlayerIndex);
if (IsPlayerAlive(p))
{
TActor *a = CArrayGet(&gActors, p->Id);
if (!a->isInUse)
{
break;
}
ActorAddAmmo(a, e->u.AddAmmo.AddAmmo);
if (e->u.AddAmmo.IsRandomSpawned)
const PlayerData *p =
CArrayGet(&gPlayerDatas, e->u.Heal.PlayerIndex);
if (IsPlayerAlive(p))
{
PowerupSpawnerRemoveOne(
CArrayGet(ammoSpawners, e->u.AddAmmo.AddAmmo.Id));
TActor *a = CArrayGet(&gActors, p->Id);
if (!a->isInUse)
{
break;
}
ActorAddAmmo(a, e->u.AddAmmo.AddAmmo);
if (e->u.AddAmmo.IsRandomSpawned)
{
PowerupSpawnerRemoveOne(
CArrayGet(ammoSpawners, e->u.AddAmmo.AddAmmo.Id));
}
// TODO: some sort of text effect showing ammo grab
}
// TODO: some sort of text effect showing ammo grab
}
}
break;
break;
case GAME_EVENT_USE_AMMO:
{
const PlayerData *p =
CArrayGet(&gPlayerDatas, e->u.UseAmmo.PlayerIndex);
if (IsPlayerAlive(p))
{
TActor *a = CArrayGet(&gActors, p->Id);
if (!a->isInUse)
const PlayerData *p =
CArrayGet(&gPlayerDatas, e->u.UseAmmo.PlayerIndex);
if (IsPlayerAlive(p))
{
break;
TActor *a = CArrayGet(&gActors, p->Id);
if (!a->isInUse)
{
break;
}
ActorAddAmmo(a, e->u.UseAmmo.UseAmmo);
// TODO: some sort of text effect showing ammo usage
}
ActorAddAmmo(a, e->u.UseAmmo.UseAmmo);
// TODO: some sort of text effect showing ammo usage
}
}
break;
break;
case GAME_EVENT_MOBILE_OBJECT_REMOVE:
MobObjDestroy(e->u.MobileObjectRemoveId);
break;
Expand Down
10 changes: 5 additions & 5 deletions src/cdogs/map.c
Expand Up @@ -433,7 +433,7 @@ bool MapTryPlaceOneObject(
Tile *t = MapGetTile(map, v);
unsigned short iMap = IMapGet(map, v);

bool isEmpty = !(t->flags & ~MAPTILE_IS_NORMAL_FLOOR) && TileIsClear(t);
const bool isEmpty = TileIsClear(t);
if (isStrictMode && !MapObjectIsTileOKStrict(
mo, iMap, isEmpty,
IMapGet(map, Vec2iNew(v.x, v.y - 1)),
Expand Down Expand Up @@ -480,9 +480,8 @@ void MapPlaceWreck(Map *map, const Vec2i v, const MapObject *mo)
{
Tile *t = MapGetTile(map, v);
unsigned short iMap = IMapGet(map, v);
bool isEmpty = !(t->flags & ~MAPTILE_IS_NORMAL_FLOOR) && TileIsClear(t);
if (!MapObjectIsTileOK(
mo, iMap, isEmpty, IMapGet(map, Vec2iNew(v.x, v.y - 1))))
mo, iMap, TileIsClear(t), IMapGet(map, Vec2iNew(v.x, v.y - 1))))
{
return;
}
Expand Down Expand Up @@ -604,6 +603,7 @@ void MapPlaceKey(
void MapPlaceAmmo(AddAmmoPickup a)
{
const Ammo *ammo = AmmoGetById(&gAmmo, a.Id);
// TODO: can explicitly link ammo to pickup without string lookup
char buf[256];
sprintf(buf, "ammo_%s", ammo->Name);
const int id = PickupAdd(Vec2iReal2Full(a.Pos), StrPickupClass(buf));
Expand All @@ -622,10 +622,10 @@ static void MapPlaceCard(Map *map, int keyIndex, int map_access)
t = MapGetTile(map, v);
iMap = IMapGet(map, v);
tBelow = MapGetTile(map, Vec2iNew(v.x, v.y + 1));
if (!(t->flags & ~MAPTILE_IS_NORMAL_FLOOR) && TileIsClear(t) &&
if (TileIsClear(t) &&
(iMap & 0xF00) == map_access &&
(iMap & MAP_MASKACCESS) == MAP_ROOM &&
!(tBelow->flags & ~MAPTILE_IS_NORMAL_FLOOR) && TileIsClear(tBelow))
TileIsClear(tBelow))
{
MapPlaceKey(map, &gMission, v, keyIndex);
return;
Expand Down
2 changes: 2 additions & 0 deletions src/cdogs/map_archive.c
Expand Up @@ -141,6 +141,8 @@ int MapNewLoadArchive(const char *filename, CampaignSetting *c)
MapObjectsLoadJSON(&gMapObjects.CustomClasses, root);
}

MapObjectsLoadAmmoSpawners(&gMapObjects, &gAmmo);


root = ReadPhysFSJSON(filename, "missions.json");
if (root == NULL)
Expand Down

0 comments on commit 228468b

Please sign in to comment.