static void LoadStaticCharacters(Mission *m, json_t *node, char *name) { CArrayInit(&m->u.Static.Characters, sizeof(CharacterPositions)); json_t *chars = json_find_first_label(node, name); if (!chars || !chars->child) { return; } chars = chars->child; for (chars = chars->child; chars; chars = chars->next) { CharacterPositions cp; LoadInt(&cp.Index, chars, "Index"); CArrayInit(&cp.Positions, sizeof(Vec2i)); json_t *positions = json_find_first_label(chars, "Positions"); if (!positions || !positions->child) { continue; } positions = positions->child; for (positions = positions->child; positions; positions = positions->next) { Vec2i pos; json_t *position = positions->child; pos.x = atoi(position->text); position = position->next; pos.y = atoi(position->text); CArrayPushBack(&cp.Positions, &pos); } CArrayPushBack(&m->u.Static.Characters, &cp); } }
static void LoadStaticKeys(Mission *m, json_t *node, char *name) { CArrayInit(&m->u.Static.Keys, sizeof(KeyPositions)); json_t *keys = json_find_first_label(node, name); if (!keys || !keys->child) { return; } keys = keys->child; for (keys = keys->child; keys; keys = keys->next) { KeyPositions kp; LoadInt(&kp.Index, keys, "Index"); CArrayInit(&kp.Positions, sizeof(Vec2i)); json_t *positions = json_find_first_label(keys, "Positions"); if (!positions || !positions->child) { continue; } positions = positions->child; for (positions = positions->child; positions; positions = positions->next) { Vec2i pos; json_t *position = positions->child; pos.x = atoi(position->text); position = position->next; pos.y = atoi(position->text); CArrayPushBack(&kp.Positions, &pos); } CArrayPushBack(&m->u.Static.Keys, &kp); } }
bool MissionStaticTryAddCharacter(Mission *m, int ch, Vec2i pos) { assert(m->Type == MAPTYPE_STATIC && "invalid map type"); unsigned short tile = MissionGetTile(m, pos); // Remove any characters already there MissionStaticTryRemoveCharacterAt(m, pos); if (IsClear(tile)) { // Check if the character already has an entry, and add to its list // of positions bool hasAdded = false; CA_FOREACH(CharacterPositions, cp, m->u.Static.Characters) if (cp->Index == ch) { CArrayPushBack(&cp->Positions, &pos); hasAdded = true; break; } CA_FOREACH_END() // If not, create a new entry if (!hasAdded) { CharacterPositions cp; cp.Index = ch; CArrayInit(&cp.Positions, sizeof(Vec2i)); CArrayPushBack(&cp.Positions, &pos); CArrayPushBack(&m->u.Static.Characters, &cp); } return true; } return false; }
void MapObjectsLoadJSON(CArray *classes, json_t *root) { int version; LoadInt(&version, root, "Version"); if (version > VERSION || version <= 0) { CASSERT(false, "cannot read map objects file version"); return; } json_t *pickupsNode = json_find_first_label(root, "MapObjects")->child; for (json_t *child = pickupsNode->child; child; child = child->next) { MapObject m; LoadMapObject(&m, child); CArrayPushBack(classes, &m); } ReloadDestructibles(&gMapObjects); // Load blood objects CArrayClear(&gMapObjects.Bloods); for (int i = 0;; i++) { char buf[CDOGS_FILENAME_MAX]; sprintf(buf, "blood%d", i); if (StrMapObject(buf) == NULL) { break; } char *tmp; CSTRDUP(tmp, buf); CArrayPushBack(&gMapObjects.Bloods, &tmp); } }
void WeaponLoadJSON(GunClasses *g, CArray *classes, json_t *root) { int version; LoadInt(&version, root, "Version"); if (version > VERSION || version <= 0) { CASSERT(false, "cannot read guns file version"); return; } GunDescription *defaultDesc = &g->Default; json_t *defaultNode = json_find_first_label(root, "DefaultGun"); if (defaultNode != NULL) { LoadGunDescription(defaultDesc, defaultNode->child, NULL); for (int i = 0; i < GUN_COUNT; i++) { CArrayPushBack(&g->Guns, defaultDesc); } } json_t *gunsNode = json_find_first_label(root, "Guns")->child; for (json_t *child = gunsNode->child; child; child = child->next) { GunDescription gd; LoadGunDescription(&gd, child, defaultDesc); int idx = -1; LoadInt(&idx, child, "Index"); CASSERT( !(idx >= 0 && idx < GUN_COUNT && classes != &g->Guns), "Cannot load gun with index as custom gun"); if (idx >= 0 && idx < GUN_COUNT && classes == &g->Guns) { memcpy(CArrayGet(&g->Guns, idx), &gd, sizeof gd); } else { CArrayPushBack(classes, &gd); } } json_t *pseudoGunsNode = json_find_first_label(root, "PseudoGuns"); if (pseudoGunsNode != NULL) { for (json_t *child = pseudoGunsNode->child->child; child; child = child->next) { GunDescription gd; LoadGunDescription(&gd, child, defaultDesc); gd.IsRealGun = false; CArrayPushBack(classes, &gd); } } }
static PlayerList *PlayerListNew( GameLoopResult (*updateFunc)(GameLoopData *, LoopRunner *), void (*drawFunc)(void *), void *data, const bool hasMenu, const bool showWinners) { PlayerList *pl; CMALLOC(pl, sizeof *pl); pl->pos = svec2i_zero(); pl->size = gGraphicsDevice.cachedConfig.Res; pl->scroll = 0; pl->updateFunc = updateFunc; pl->drawFunc = drawFunc; pl->data = data; pl->hasMenu = hasMenu; pl->showWinners = showWinners; CArrayInit(&pl->playerUIDs, sizeof(int)); // Collect all players, then order by score descending int playersAlive = 0; CA_FOREACH(const PlayerData, p, gPlayerDatas) CArrayPushBack(&pl->playerUIDs, &p->UID); if (p->Lives > 0) { playersAlive++; } CA_FOREACH_END() qsort( pl->playerUIDs.data, pl->playerUIDs.size, pl->playerUIDs.elemSize, ComparePlayerScores); pl->showLastMan = playersAlive == 1; return pl; }
void BulletLoadJSON( BulletClasses *bullets, CArray *classes, json_t *bulletNode) { int version; LoadInt(&version, bulletNode, "Version"); if (version > VERSION || version <= 0) { CASSERT(false, "cannot read bullets file version"); return; } // Defaults json_t *defaultNode = json_find_first_label(bulletNode, "DefaultBullet"); if (defaultNode != NULL) { BulletClassFree(&bullets->Default); LoadBullet(&bullets->Default, defaultNode->child, NULL); } json_t *bulletsNode = json_find_first_label(bulletNode, "Bullets")->child; for (json_t *child = bulletsNode->child; child; child = child->next) { BulletClass b; LoadBullet(&b, child, &bullets->Default); CArrayPushBack(classes, &b); } bullets->root = bulletNode; }
static void DrawWallsAndThings(DrawBuffer *b, Vec2i offset) { Vec2i pos; Tile *tile = &b->tiles[0][0]; pos.y = b->dy + cWallOffset.dy + offset.y; for (int y = 0; y < Y_TILES; y++, pos.y += TILE_HEIGHT) { CArrayClear(&b->displaylist); pos.x = b->dx + cWallOffset.dx + offset.x; for (int x = 0; x < b->Size.x; x++, tile++, pos.x += TILE_WIDTH) { if (tile->flags & MAPTILE_IS_WALL) { if (!(tile->flags & MAPTILE_DELAY_DRAW)) { DrawWallColumn(y, pos, tile); } } else if (tile->flags & MAPTILE_OFFSET_PIC) { // Drawing doors // Doors may be offset; vertical doors are drawn centered // horizontal doors are bottom aligned Vec2i doorPos = pos; doorPos.x += (TILE_WIDTH - tile->picAlt->pic.size.x) / 2; if (tile->picAlt->pic.size.y > 16) { doorPos.y += TILE_HEIGHT - (tile->picAlt->pic.size.y % TILE_HEIGHT); } BlitMasked( &gGraphicsDevice, &tile->picAlt->pic, doorPos, GetTileLOSMask(tile), 0); } // Draw the items that are in LOS if (tile->flags & MAPTILE_OUT_OF_SIGHT) { continue; } CA_FOREACH(ThingId, tid, tile->things) const TTileItem *ti = ThingIdGetTileItem(tid); // Don't draw debris, they are drawn later if (TileItemIsDebris(ti)) { continue; } CArrayPushBack(&b->displaylist, &ti); CA_FOREACH_END() } DrawBufferSortDisplayList(b); CA_FOREACH(const TTileItem *, tp, b->displaylist) DrawThing(b, *tp, offset); CA_FOREACH_END() tile += X_TILES - b->Size.x; } }
static void DrawDebris(DrawBuffer *b, Vec2i offset) { Tile *tile = &b->tiles[0][0]; for (int y = 0; y < Y_TILES; y++) { CArrayClear(&b->displaylist); for (int x = 0; x < b->Size.x; x++, tile++) { if (tile->flags & MAPTILE_OUT_OF_SIGHT) { continue; } CA_FOREACH(ThingId, tid, tile->things) const TTileItem *ti = ThingIdGetTileItem(tid); if (TileItemIsDebris(ti)) { CArrayPushBack(&b->displaylist, &ti); } CA_FOREACH_END() } DrawBufferSortDisplayList(b); CA_FOREACH(const TTileItem *, tp, b->displaylist) DrawThing(b, *tp, offset); CA_FOREACH_END() tile += X_TILES - b->Size.x; } }
Action *TriggerAddAction(Trigger *t) { Action a; memset(&a, 0, sizeof a); CArrayPushBack(&t->actions, &a); return CArrayGet(&t->actions, t->actions.size - 1); }
Action *WatchAddAction(TWatch *w) { Action a; memset(&a, 0, sizeof a); CArrayPushBack(&w->actions, &a); return CArrayGet(&w->actions, w->actions.size - 1); }
void HighScoresInit(void) { CArrayInit(&HighScores, sizeof(HighScore)); char buf[MAX_PATH]; get_user_config_file(buf, MAX_PATH, HIGH_SCORE_FILE); if (strlen(buf) == 0) { printf("Error: cannot find config file path\n"); return; } FILE *f = fopen(buf, "r"); if (f == NULL) { printf("Error: cannot open config file %s\n", buf); return; } while (fgets(buf, sizeof buf, f)) { HighScore hs; struct tm tm; sscanf( buf, "%d %04d-%02d-%02d %02d:%02d:%02d", &hs.Score, &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec); // Time correction tm.tm_year -= 1900; tm.tm_mon--; hs.Time = mktime(&tm); CArrayPushBack(&HighScores, &hs); } fclose(f); }
Condition *WatchAddCondition(TWatch *w) { Condition c; memset(&c, 0, sizeof c); CArrayPushBack(&w->conditions, &c); return CArrayGet(&w->conditions, w->conditions.size - 1); }
static void DrawDebris(DrawBuffer *b, struct vec2i offset) { Tile *tile = &b->tiles[0][0]; for (int y = 0; y < Y_TILES; y++) { CArrayClear(&b->displaylist); for (int x = 0; x < b->Size.x; x++, tile++) { if (tile->outOfSight) { continue; } CA_FOREACH(ThingId, tid, tile->things) const Thing *ti = ThingIdGetThing(tid); if (ThingDrawLast(ti)) { CArrayPushBack(&b->displaylist, &ti); } CA_FOREACH_END() } DrawBufferSortDisplayList(b); CA_FOREACH(const Thing *, tp, b->displaylist) DrawThing(b, *tp, offset); CA_FOREACH_END() tile += X_TILES - b->Size.x; } }
void UIObjectDraw( UIObject *o, GraphicsDevice *g, Vec2i pos, Vec2i mouse, CArray *drawObjs) { // Draw this UIObject and its children in BFS order // Maintain a queue of UIObjects to draw if (drawObjs->elemSize == 0) { CArrayInit(drawObjs, sizeof(UIObjectDrawContext)); UIObjectDrawContext c; c.obj = o; c.pos = pos; CArrayPushBack(drawObjs, &c); for (int i = 0; i < (int)drawObjs->size; i++) { UIObjectDrawContext *cPtr = CArrayGet(drawObjs, i); UIObjectDrawAndAddChildren( cPtr->obj, g, cPtr->pos, mouse, drawObjs); } } else { for (int i = 0; i < (int)drawObjs->size; i++) { UIObjectDrawContext *cPtr = CArrayGet(drawObjs, i); UIObjectDrawAndAddChildren( cPtr->obj, g, cPtr->pos, mouse, NULL); } } }
void SetupMission( int buildTables, Mission *m, struct MissionOptions *mo, int missionIndex) { int i; MissionOptionsInit(mo); mo->index = missionIndex; mo->missionData = m; mo->doorPics = doorStyles[abs(m->DoorStyle) % DOORSTYLE_COUNT]; mo->keyPics = keyStyles[abs(m->KeyStyle) % KEYSTYLE_COUNT]; for (i = 0; i < (int)m->Items.size; i++) { CArrayPushBack( &mo->MapObjects, MapObjectGet(*(int32_t *)CArrayGet(&m->Items, i))); } mo->exitPic = exitPics[2 * (abs(m->ExitStyle) % EXIT_COUNT)]; mo->exitShadow = exitPics[2 * (abs(m->ExitStyle) % EXIT_COUNT) + 1]; ActorsInit(); ObjsInit(); MobObjsInit(); SetupObjectives(mo, m); SetupBadguysForMission(m); SetupWeapons(gPlayerDatas, &m->Weapons); SetPaletteRanges(m->WallColor, m->FloorColor, m->RoomColor, m->AltColor); if (buildTables) { BuildTranslationTables(gPicManager.palette); } }
void MissionConvertToType(Mission *m, Map *map, MapType type) { memset(&m->u, 0, sizeof m->u); switch (type) { case MAPTYPE_CLASSIC: // Setup default parameters m->u.Classic.Walls = 10; m->u.Classic.WallLength = 5; m->u.Classic.CorridorWidth = 2; m->u.Classic.Rooms.Count = 10; m->u.Classic.Rooms.Min = 5; m->u.Classic.Rooms.Max = 8;; m->u.Classic.Rooms.Edge = true; m->u.Classic.Rooms.Overlap = true; m->u.Classic.Rooms.Walls = 1; m->u.Classic.Rooms.WallLength = 1; m->u.Classic.Rooms.WallPad = 1; m->u.Classic.Squares = 1; m->u.Classic.Doors.Enabled = true; m->u.Classic.Doors.Min = 1; m->u.Classic.Doors.Max = 2; m->u.Classic.Pillars.Count = 1; m->u.Classic.Pillars.Min = 2; m->u.Classic.Pillars.Max = 3; break; case MAPTYPE_STATIC: { Vec2i v; // Take all the tiles from the current map // and save them in the static map CArrayInit(&m->u.Static.Tiles, sizeof(unsigned short)); for (v.y = 0; v.y < m->Size.y; v.y++) { for (v.x = 0; v.x < m->Size.x; v.x++) { unsigned short tile = IMapGet(map, v); CArrayPushBack(&m->u.Static.Tiles, &tile); } } CArrayInit(&m->u.Static.Items, sizeof(MapObjectPositions)); CArrayInit(&m->u.Static.Characters, sizeof(CharacterPositions)); CArrayInit(&m->u.Static.Objectives, sizeof(ObjectivePositions)); CArrayInit(&m->u.Static.Keys, sizeof(KeyPositions)); } break; case MAPTYPE_CAVE: // Setup default parameters m->u.Cave.FillPercent = 40; m->u.Cave.Repeat = 4; m->u.Cave.R1 = 5; m->u.Cave.R2 = 2; m->u.Cave.CorridorWidth = 2; break; default: CASSERT(false, "unknown map type"); break; } m->Type = type; }
void ConvertCampaignSetting(CampaignSetting *dest, CampaignSettingOld *src) { int i; CFREE(dest->Title); CSTRDUP(dest->Title, src->title); CFREE(dest->Author); CSTRDUP(dest->Author, src->author); CFREE(dest->Description); CSTRDUP(dest->Description, src->description); for (i = 0; i < src->missionCount; i++) { Mission m; MissionInit(&m); ConvertMission(&m, &src->missions[i]); CArrayPushBack(&dest->Missions, &m); } CharacterStoreTerminate(&dest->characters); CharacterStoreInit(&dest->characters); for (i = 0; i < src->characterCount; i++) { Character *ch = CharacterStoreAddOther(&dest->characters); ConvertCharacter(ch, &src->characters[i]); CharacterSetLooks(ch, &ch->looks); } }
void SoundAdd(CArray *sounds, const char *name, Mix_Chunk *data) { SoundData sound; sound.data = data; strcpy(sound.Name, name); CArrayPushBack(sounds, &sound); }
static void LoadGunSpawners(CArray *classes, const CArray *guns) { for (int i = 0; i < (int)guns->size; i++) { const GunDescription *g = CArrayGet(guns, i); if (!g->IsRealGun) { continue; } MapObject m; memset(&m, 0, sizeof m); char buf[256]; sprintf(buf, "%s spawner", g->name); CSTRDUP(m.Name, buf); m.Normal.Pic = PicManagerGetPic(&gPicManager, "spawn_pad"); m.Normal.Offset = Vec2iNew( -m.Normal.Pic->size.x / 2, TILE_HEIGHT / 2 - m.Normal.Pic->size.y); m.Size = Vec2iNew(TILE_WIDTH, TILE_HEIGHT); m.Health = 0; m.Type = MAP_OBJECT_TYPE_PICKUP_SPAWNER; sprintf(buf, "gun_%s", g->name); m.u.PickupClass = StrPickupClass(buf); CArrayPushBack(classes, &m); } }
void GameEventsEnqueue(CArray *store, GameEvent e) { if (store->elemSize == 0) { return; } // If we're the server, broadcast any events that clients need switch (e.Type) { case GAME_EVENT_ACTOR_ADD: NetServerBroadcastMsg( &gNetServer, SERVER_MSG_ACTOR_ADD, &e.u.ActorAdd); break; case GAME_EVENT_ACTOR_MOVE: NetServerBroadcastMsg( &gNetServer, SERVER_MSG_ACTOR_MOVE, &e.u.ActorMove); break; case GAME_EVENT_MISSION_END: NetServerBroadcastMsg(&gNetServer, SERVER_MSG_GAME_END, NULL); break; default: // do nothing break; } CArrayPushBack(store, &e); }
static bool TryLoadStaticMap(Mission *m, json_t *node, int version) { CArrayInit(&m->u.Static.Tiles, sizeof(unsigned short)); if (version == 1) { // JSON array json_t *tiles = json_find_first_label(node, "Tiles"); if (!tiles || !tiles->child) { return false; } tiles = tiles->child; for (tiles = tiles->child; tiles; tiles = tiles->next) { unsigned short n = (unsigned short)atoi(tiles->text); CArrayPushBack(&m->u.Static.Tiles, &n); } } else { // CSV string char *tileCSV = GetString(node, "Tiles"); char *pch = strtok(tileCSV, ","); while (pch != NULL) { unsigned short n = (unsigned short)atoi(pch); CArrayPushBack(&m->u.Static.Tiles, &n); pch = strtok(NULL, ","); } CFREE(tileCSV); } CArrayInit(&m->u.Static.Items, sizeof(MapObjectPositions)); LoadStaticItems(m, node, "StaticItems", version); if (version < 13) { LoadStaticItems(m, node, "StaticWrecks", version); } LoadStaticCharacters(m, node, "StaticCharacters"); LoadStaticObjectives(m, node, "StaticObjectives"); LoadStaticKeys(m, node, "StaticKeys"); LoadVec2i(&m->u.Static.Start, node, "Start"); LoadStaticExit(m, node, "Exit"); return true; }
void MenuSystemAddCustomDisplay( MenuSystem *ms, MenuDisplayFunc func, void *data) { MenuCustomDisplayFunc cdf; cdf.Func = func; cdf.Data = data; CArrayPushBack(&ms->customDisplayFuncs, &cdf); }
void MenuAddExitType(MenuSystem *menu, menu_type_e exitType) { if (MenuHasExitType(menu, exitType)) { return; } CArrayPushBack(&menu->exitTypes, &exitType); }
static void LoadCampaignsFromFolder( campaign_list_t *list, const char *name, const char *path, const GameMode mode) { tinydir_dir dir; int i; CSTRDUP(list->Name, name); if (tinydir_open_sorted(&dir, path) == -1) { printf("Cannot load campaigns from path %s\n", path); return; } for (i = 0; i < (int)dir.n_files; i++) { tinydir_file file; tinydir_readfile_n(&dir, &file, i); // Ignore campaigns that start with a ~ // These are autosaved const bool isArchive = strcmp(file.extension, "cdogscpn") == 0 || strcmp(file.extension, "CDOGSCPN") == 0; if (file.is_dir && !isArchive && strcmp(file.name, ".") != 0 && strcmp(file.name, "..") != 0) { campaign_list_t subFolder; CampaignListInit(&subFolder); LoadCampaignsFromFolder(&subFolder, file.name, file.path, mode); CArrayPushBack(&list->subFolders, &subFolder); } else if ((file.is_reg || isArchive) && file.name[0] != '~') { CampaignEntry entry; if (CampaignEntryTryLoad(&entry, file.path, mode)) { CArrayPushBack(&list->list, &entry); } } } tinydir_close(&dir); }
void SoundInitialize(SoundDevice *device, const char *path) { memset(device, 0, sizeof *device); if (OpenAudio(44100, AUDIO_S16, 2, 1024) != 0) { return; } device->channels = 64; SoundReconfigure(device); CArrayInit(&device->sounds, sizeof(SoundData)); CArrayInit(&device->customSounds, sizeof(SoundData)); SoundLoadDirImpl(device, path, NULL); // Look for commonly used sounds to set our pointers CArrayInit(&device->footstepSounds, sizeof(Mix_Chunk *)); for (int i = 0;; i++) { char buf[CDOGS_FILENAME_MAX]; sprintf(buf, "footsteps/%d", i); Mix_Chunk *s = StrSound(buf); if (s == NULL) break; CArrayPushBack(&device->footstepSounds, &s); } device->slideSound = StrSound("slide"); device->healthSound = StrSound("health"); device->clickSound = StrSound("click"); device->keySound = StrSound("key"); device->wreckSound = StrSound("bang"); CArrayInit(&device->screamSounds, sizeof(Mix_Chunk *)); for (int i = 0;; i++) { char buf[CDOGS_FILENAME_MAX]; sprintf(buf, "aargh%d", i); Mix_Chunk *scream = StrSound(buf); if (scream == NULL) { break; } CArrayPushBack(&device->screamSounds, &scream); } }
static void AddObjective(Mission *m) { // TODO: support more objectives if (m->Objectives.size < OBJECTIVE_MAX_OLD) { MissionObjective mo; memset(&mo, 0, sizeof mo); CArrayPushBack(&m->Objectives, &mo); } }
void GameEventsEnqueue(CArray *store, GameEvent e) { // Hack: sometimes trigger events are added by placing enemies // before the game events has been initialised // Just ignore for now if (store->elemSize == 0) { return; } CArrayPushBack(store, &e); }
static void AddWeapon(CArray *weapons, const CArray *guns) { for (int i = 0; i < (int)guns->size; i++) { const GunDescription *g = CArrayGet(guns, i); if (g->IsRealGun) { CArrayPushBack(weapons, &g); } } }
static void AllowedWeaponsDataInit( AllowedWeaponsData *data, const CArray *weapons) { data->weapons = weapons; CArrayInit(&data->allowed, sizeof(bool)); for (int i = 0; i < (int)weapons->size; i++) { const bool f = true; CArrayPushBack(&data->allowed, &f); } }