const char *GetHomeDirectory(void) { const char *p; if (cdogs_homepath != NULL) { return cdogs_homepath; } p = getenv("CDOGS_CONFIG_DIR"); if (p != NULL && strlen(p) != 0) { CSTRDUP(cdogs_homepath, p); return cdogs_homepath; } p = getenv(HOME_DIR_ENV); if (p != NULL && strlen(p) != 0) { CCALLOC(cdogs_homepath, strlen(p) + 2); strcpy(cdogs_homepath, p); cdogs_homepath[strlen(p)] = '/'; return cdogs_homepath; } fprintf(stderr,"%s%s%s%s", "##############################################################\n", "# You don't have the environment variables HOME or USER set. #\n", "# It is suggested you get a better shell. :D #\n", "##############################################################\n"); return ""; }
static inline ASNeighborList NeighborListCreate(const ASPathNodeSource *source) { ASNeighborList list; CCALLOC(list, sizeof(struct __ASNeighborList)); list->source = source; return list; }
UIObject *UIObjectCreate(UIType type, int id, Vec2i pos, Vec2i size) { UIObject *o; CCALLOC(o, sizeof *o); o->Type = type; o->Id = id; o->Pos = pos; o->Size = size; o->IsVisible = true; switch (type) { case UITYPE_TEXTBOX: o->u.Textbox.IsEditable = 1; o->ChangesData = 1; break; case UITYPE_TAB: CArrayInit(&o->u.Tab.Labels, sizeof(char *)); o->u.Tab.Index = 0; break; case UITYPE_CONTEXT_MENU: // Context menu always starts as invisible o->IsVisible = false; break; default: // do nothing break; } CArrayInit(&o->Children, sizeof o); return o; }
static json_t *SaveStaticTiles(Mission *m) { // Create a text buffer for CSV // The buffer will contain n*5 chars (tiles, allow 5 chars each), // and n - 1 commas, so 6n total const int size = (int)m->u.Static.Tiles.size; if (size == 0) { return json_new_string(""); } char *bigbuf; CCALLOC(bigbuf, size * 6); char *pBuf = bigbuf; CASSERT(pBuf != NULL, "memory error"); for (int i = 0; i < size; i++) { char buf[32]; sprintf(buf, "%d", *(unsigned short *)CArrayGet( &m->u.Static.Tiles, i)); strcpy(pBuf, buf); pBuf += strlen(buf); if (i < size - 1) { *pBuf = ','; pBuf++; } } json_t *node = json_new_string(bigbuf); CFREE(bigbuf); return node; }
bool ScreenMissionBriefing(const struct MissionOptions *m) { const int w = gGraphicsDevice.cachedConfig.Res.x; const int h = gGraphicsDevice.cachedConfig.Res.y; const int y = h / 4; MissionBriefingData mData; memset(&mData, 0, sizeof mData); mData.IsOK = true; // Title CMALLOC(mData.Title, strlen(m->missionData->Title) + 32); sprintf(mData.Title, "Mission %d: %s", m->index + 1, m->missionData->Title); mData.TitleOpts = FontOptsNew(); mData.TitleOpts.HAlign = ALIGN_CENTER; mData.TitleOpts.Area = gGraphicsDevice.cachedConfig.Res; mData.TitleOpts.Pad.y = y - 25; // Password if (m->index > 0) { sprintf( mData.Password, "Password: %s", gAutosave.LastMission.Password); mData.PasswordOpts = FontOptsNew(); mData.PasswordOpts.HAlign = ALIGN_CENTER; mData.PasswordOpts.Area = gGraphicsDevice.cachedConfig.Res; mData.PasswordOpts.Pad.y = y - 15; } // Split the description, and prepare it for typewriter effect mData.TypewriterCount = 0; // allow some slack for newlines CMALLOC(mData.Description, strlen(m->missionData->Description) * 2 + 1); CCALLOC(mData.TypewriterBuf, strlen(m->missionData->Description) * 2 + 1); // Pad about 1/6th of the screen width total (1/12th left and right) FontSplitLines(m->missionData->Description, mData.Description, w * 5 / 6); mData.DescriptionPos = Vec2iNew(w / 12, y); // Objectives mData.ObjectiveDescPos = Vec2iNew(w / 6, y + FontStrH(mData.Description) + h / 10); mData.ObjectiveInfoPos = Vec2iNew(w - (w / 6), mData.ObjectiveDescPos.y + FontH()); mData.ObjectiveHeight = h / 12; mData.MissionOptions = m; GameLoopData gData = GameLoopDataNew( &mData, MissionBriefingUpdate, &mData, MissionBriefingDraw); GameLoop(&gData); if (mData.IsOK) { SoundPlay(&gSoundDevice, StrSound("mg")); } CFREE(mData.Title); CFREE(mData.Description); CFREE(mData.TypewriterBuf); return mData.IsOK; }
Trigger *TriggerNew(void) { Trigger *t; CCALLOC(t, sizeof *t); t->isActive = 1; CArrayInit(&t->actions, sizeof(Action)); return t; }
static inline VisitedNodes VisitedNodesCreate(const ASPathNodeSource *source, void *context) { VisitedNodes nodes; CCALLOC(nodes, sizeof(struct __VisitedNodes)); nodes->source = source; nodes->context = context; return nodes; }
menu_t *MenuCreate(const char *name, menu_type_e type) { menu_t *menu; CCALLOC(menu, sizeof(menu_t)); CSTRDUP(menu->name, name); menu->type = type; menu->parentMenu = NULL; return menu; }
AIContext *AIContextNew(void) { AIContext *c; CCALLOC(c, sizeof *c); // Initialise chatter counter so we don't say anything in the background c->ChatterCounter = 2; c->EnemyId = -1; c->GunRangeScalar = 1.0; return c; }
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 *AddWatch(int conditionCount, int actionCount) { TWatch *t; CCALLOC(t, sizeof(TWatch)); t->index = watchIndex++; t->next = inactiveWatches; inactiveWatches = t; t->actions = AddActions(actionCount); t->conditions = AddConditions(conditionCount); return t; }
static char *ReadFileIntoBuf(const char *path, const char *mode, long *len) { char *buf = NULL; FILE *f = fopen(path, mode); if (f == NULL) { debug(D_NORMAL, "Did not open file %s: %s.\n", path, strerror(errno)); goto bail; } // Read into buffer if (fseek(f, 0L, SEEK_END) != 0) { debug(D_NORMAL, "Cannot seek file %s: %s.\n", path, strerror(errno)); goto bail; } *len = ftell(f); if (*len == -1) { debug(D_NORMAL, "Cannot tell file %s: %s.\n", path, strerror(errno)); goto bail; } CCALLOC(buf, *len + 1); if (fseek(f, 0L, SEEK_SET) != 0) { debug(D_NORMAL, "Cannot seek file %s: %s.\n", path, strerror(errno)); goto bail; } if (fread(buf, 1, *len, f) == 0) { debug(D_NORMAL, "Cannot read file %s: %s.\n", path, strerror(errno)); goto bail; } goto end; bail: CFREE(buf); buf = NULL; end: if (f != NULL && fclose(f) != 0) { debug(D_NORMAL, "Cannot close file %s: %s.\n", path, strerror(errno)); } return buf; }
TTrigger *AddTrigger(int x, int y, int actionCount) { TTrigger *t; TTrigger **h; CCALLOC(t, sizeof(TTrigger)); t->x = x; t->y = y; h = &root; while (*h) { if ((*h)->y < y || ((*h)->y == y && (*h)->x < x)) h = &((*h)->right); else h = &((*h)->left); } *h = t; t->actions = AddActions(actionCount); return t; }
static TCondition *AddConditions(int count) { TCondition *a; CCALLOC(a, sizeof(TCondition) * (count + 1)); return a; }
// Initialises the video subsystem. // To prevent needless screen flickering, config is compared with cache // to see if anything changed. If not, don't recreate the screen. void GraphicsInitialize( GraphicsDevice *device, GraphicsConfig *config, TPalette palette, int force) { int sdl_flags = 0; unsigned int w, h = 0; unsigned int rw, rh; if (!IsRestartRequiredForConfig(device, config)) { return; } if (!device->IsWindowInitialized) { /* only do this the first time */ char title[32]; debug(D_NORMAL, "setting caption and icon...\n"); sprintf(title, "C-Dogs SDL %s%s", config->IsEditor ? "Editor " : "", CDOGS_SDL_VERSION); SDL_WM_SetCaption(title, NULL); device->icon = SDL_LoadBMP(GetDataFilePath("cdogs_icon.bmp")); SDL_WM_SetIcon(device->icon, NULL); AddSupportedGraphicsModes(device); } device->IsInitialized = 0; sdl_flags |= SDL_SWSURFACE; sdl_flags |= config->IsEditor ? SDL_RESIZABLE : 0; if (config->Fullscreen) { sdl_flags |= SDL_FULLSCREEN; } rw = w = config->Res.x; rh = h = config->Res.y; if (config->ScaleFactor > 1) { rw *= config->ScaleFactor; rh *= config->ScaleFactor; } if (!force && !config->IsEditor) { device->modeIndex = FindValidMode(device, w, h, config->ScaleFactor); if (device->modeIndex == -1) { device->modeIndex = 0; printf("!!! Invalid Video Mode %dx%d\n", w, h); return; } } else { printf("\n"); printf(" BIG FAT WARNING: If this blows up in your face,\n"); printf(" and mutilates your cat, please don't cry.\n"); printf("\n"); } printf("Graphics mode:\t%dx%d %dx (actual %dx%d)\n", w, h, config->ScaleFactor, rw, rh); SDL_FreeSurface(device->screen); device->screen = SDL_SetVideoMode(rw, rh, 32, sdl_flags); if (device->screen == NULL) { printf("ERROR: InitVideo: %s\n", SDL_GetError()); return; } SDL_PixelFormat *f = device->screen->format; device->Amask = -1 & ~(f->Rmask | f->Gmask | f->Bmask); Uint32 aMask = device->Amask; device->Ashift = 0; while (aMask != 0xff) { device->Ashift += 8; aMask >>= 8; } CFREE(device->buf); CCALLOC(device->buf, GraphicsGetMemSize(config)); CFREE(device->bkg); CCALLOC(device->bkg, GraphicsGetMemSize(config)); debug(D_NORMAL, "Changed video mode...\n"); GraphicsSetBlitClip( device, 0, 0, config->Res.x - 1,config->Res.y - 1); debug(D_NORMAL, "Internal dimensions:\t%dx%d\n", config->Res.x, config->Res.y); device->IsInitialized = 1; device->IsWindowInitialized = 1; device->cachedConfig = *config; device->cachedConfig.Res.x = w; device->cachedConfig.Res.y = h; CDogsSetPalette(palette); }
// Initialises the video subsystem. // To prevent needless screen flickering, config is compared with cache // to see if anything changed. If not, don't recreate the screen. void GraphicsInitialize(GraphicsDevice *g, const bool force) { #ifdef __GCWZERO__ int sdl_flags = SDL_HWSURFACE | SDL_TRIPLEBUF; #else int sdl_flags = SDL_SWSURFACE; #endif unsigned int w, h = 0; unsigned int rw, rh; if (g->IsInitialized && !g->cachedConfig.needRestart) { return; } if (!g->IsWindowInitialized) { /* only do this the first time */ char title[32]; debug(D_NORMAL, "setting caption and icon...\n"); sprintf(title, "C-Dogs SDL %s%s", g->cachedConfig.IsEditor ? "Editor " : "", CDOGS_SDL_VERSION); SDL_WM_SetCaption(title, NULL); char buf[CDOGS_PATH_MAX]; GetDataFilePath(buf, "cdogs_icon.bmp"); g->icon = SDL_LoadBMP(buf); SDL_WM_SetIcon(g->icon, NULL); AddSupportedGraphicsModes(g); } g->IsInitialized = false; sdl_flags |= g->cachedConfig.IsEditor ? SDL_RESIZABLE : 0; if (g->cachedConfig.Fullscreen) { sdl_flags |= SDL_FULLSCREEN; } rw = w = g->cachedConfig.Res.x; rh = h = g->cachedConfig.Res.y; if (g->cachedConfig.ScaleFactor > 1) { rw *= g->cachedConfig.ScaleFactor; rh *= g->cachedConfig.ScaleFactor; } if (!force && !g->cachedConfig.IsEditor) { g->modeIndex = FindValidMode(g, w, h, g->cachedConfig.ScaleFactor); if (g->modeIndex == -1) { g->modeIndex = 0; printf("!!! Invalid Video Mode %dx%d\n", w, h); return; } } printf("Graphics mode:\t%dx%d %dx (actual %dx%d)\n", w, h, g->cachedConfig.ScaleFactor, rw, rh); SDL_FreeSurface(g->screen); g->screen = SDL_SetVideoMode(rw, rh, 32, sdl_flags); if (g->screen == NULL) { printf("ERROR: InitVideo: %s\n", SDL_GetError()); return; } SDL_PixelFormat *f = g->screen->format; g->Amask = -1 & ~(f->Rmask | f->Gmask | f->Bmask); Uint32 aMask = g->Amask; g->Ashift = 0; while (aMask != 0xff) { g->Ashift += 8; aMask >>= 8; } CFREE(g->buf); CCALLOC(g->buf, GraphicsGetMemSize(&g->cachedConfig)); CFREE(g->bkg); CCALLOC(g->bkg, GraphicsGetMemSize(&g->cachedConfig)); debug(D_NORMAL, "Changed video mode...\n"); GraphicsSetBlitClip( g, 0, 0, g->cachedConfig.Res.x - 1, g->cachedConfig.Res.y - 1); debug(D_NORMAL, "Internal dimensions:\t%dx%d\n", g->cachedConfig.Res.x, g->cachedConfig.Res.y); g->IsInitialized = true; g->IsWindowInitialized = true; g->cachedConfig.Res.x = w; g->cachedConfig.Res.y = h; g->cachedConfig.needRestart = false; }
static void CreateAddMapItemSubObjs(UIObject *c, void *vData) { const CreateAddMapItemObjsImplData *data = vData; const int pageSize = data->GridSize.x * data->GridSize.y; // Check if we need to recreate the objs // TODO: this is a very heavyweight way to do it int count = 0; bool allChildrenSame = true; for (int i = 0; i < MapObjectsCount(&gMapObjects); i++) { MapObject *mo = IndexMapObject(i); UIObject *o2 = UIObjectCreate(UITYPE_CUSTOM, 0, svec2i_zero(), data->GridItemSize); o2->IsDynamicData = true; CCALLOC(o2->Data, data->DataSize); if (!data->ObjFunc(o2, mo, data->Data)) { UIObjectDestroy(o2); continue; } const int pageIdx = count / pageSize; if (pageIdx >= (int)c->Children.size) { allChildrenSame = false; break; } const UIObject **op = CArrayGet(&c->Children, pageIdx); const UIObject **octx = CArrayGet(&(*op)->Children, 0); const int idx = count % pageSize; if (idx >= (int)(*octx)->Children.size) { allChildrenSame = false; break; } const UIObject **oc = CArrayGet(&(*octx)->Children, idx); if (memcmp(o2->Data, (*oc)->Data, data->DataSize) != 0) { allChildrenSame = false; UIObjectDestroy(o2); break; } count++; UIObjectDestroy(o2); } int cCount = CountAddMapItemSubObjs(c); if (cCount == count && allChildrenSame) { return; } // Recreate the child UI objects c->Highlighted = NULL; UIObject **objs = c->Children.data; for (int i = 0; i < (int)c->Children.size; i++, objs++) { UIObjectDestroy(*objs); } CArrayClear(&c->Children); // Create pagination int pageNum = 1; UIObject *pageLabel = NULL; UIObject *page = NULL; UIObject *o = UIObjectCreate(UITYPE_CUSTOM, 0, svec2i_zero(), data->GridItemSize); o->ChangesData = true; const struct vec2i gridStart = svec2i_zero(); struct vec2i pos = svec2i_zero(); count = 0; for (int i = 0; i < MapObjectsCount(&gMapObjects); i++) { // Only add normal map objects MapObject *mo = IndexMapObject(i); UIObject *o2 = UIObjectCopy(o); o2->IsDynamicData = true; CCALLOC(o2->Data, data->DataSize); if (!data->ObjFunc(o2, mo, data->Data)) { UIObjectDestroy(o2); continue; } o2->Pos = pos; if (count == 0) { pageLabel = UIObjectCreate( UITYPE_LABEL, 0, svec2i((pageNum - 1) * 10, 0), svec2i(10, FontH())); char buf[32]; sprintf(buf, "%d", pageNum); UIObjectSetDynamicLabel(pageLabel, buf); page = UIObjectCreate( UITYPE_CONTEXT_MENU, 0, svec2i_add(data->PageOffset, pageLabel->Size), svec2i_zero()); UIObjectAddChild(pageLabel, page); pageNum++; } UIObjectAddChild(page, o2); pos.x += o->Size.x; if (((count + 1) % data->GridSize.x) == 0) { pos.x = gridStart.x; pos.y += o->Size.y; } count++; if (count == pageSize) { count = 0; pos = gridStart; UIObjectAddChild(c, pageLabel); } } if (pageLabel != NULL) { UIObjectAddChild(c, pageLabel); } UIObjectDestroy(o); }
void GraphicsInitialize(GraphicsDevice *g) { if (g->IsInitialized && !g->cachedConfig.RestartFlags) { return; } if (!g->IsWindowInitialized) { char buf[CDOGS_PATH_MAX]; GetDataFilePath(buf, "cdogs_icon.bmp"); g->icon = IMG_Load(buf); AddSupportedGraphicsModes(g); g->IsWindowInitialized = true; } g->IsInitialized = false; const int w = g->cachedConfig.Res.x; const int h = g->cachedConfig.Res.y; const bool initRenderer = !!(g->cachedConfig.RestartFlags & RESTART_RESOLUTION); const bool initTextures = !!(g->cachedConfig.RestartFlags & (RESTART_RESOLUTION | RESTART_SCALE_MODE)); const bool initBrightness = !!(g->cachedConfig.RestartFlags & (RESTART_RESOLUTION | RESTART_SCALE_MODE | RESTART_BRIGHTNESS)); if (initRenderer) { Uint32 sdlFlags = SDL_WINDOW_RESIZABLE; if (g->cachedConfig.Fullscreen) { sdlFlags |= SDL_WINDOW_FULLSCREEN; } LOG(LM_GFX, LL_INFO, "graphics mode(%dx%d %dx)", w, h, g->cachedConfig.ScaleFactor); // Get the previous window's size and recreate it Vec2i windowSize = Vec2iNew( w * g->cachedConfig.ScaleFactor, h * g->cachedConfig.ScaleFactor); if (g->window) { SDL_GetWindowSize(g->window, &windowSize.x, &windowSize.y); } LOG(LM_GFX, LL_DEBUG, "destroying previous renderer"); SDL_DestroyTexture(g->screen); SDL_DestroyTexture(g->bkg); SDL_DestroyTexture(g->brightnessOverlay); SDL_DestroyRenderer(g->renderer); SDL_FreeFormat(g->Format); SDL_DestroyWindow(g->window); LOG(LM_GFX, LL_DEBUG, "creating window %dx%d flags(%X)", windowSize.x, windowSize.y, sdlFlags); if (SDL_CreateWindowAndRenderer( windowSize.x, windowSize.y, sdlFlags, &g->window, &g->renderer) == -1 || g->window == NULL || g->renderer == NULL) { LOG(LM_GFX, LL_ERROR, "cannot create window or renderer: %s", SDL_GetError()); return; } char title[32]; sprintf(title, "C-Dogs SDL %s%s", g->cachedConfig.IsEditor ? "Editor " : "", CDOGS_SDL_VERSION); LOG(LM_GFX, LL_DEBUG, "setting title(%s) and icon", title); SDL_SetWindowTitle(g->window, title); SDL_SetWindowIcon(g->window, g->icon); g->Format = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888); if (SDL_RenderSetLogicalSize(g->renderer, w, h) != 0) { LOG(LM_GFX, LL_ERROR, "cannot set renderer logical size: %s", SDL_GetError()); return; } GraphicsSetBlitClip( g, 0, 0, g->cachedConfig.Res.x - 1, g->cachedConfig.Res.y - 1); } if (initTextures) { if (!initRenderer) { SDL_DestroyTexture(g->screen); SDL_DestroyTexture(g->bkg); SDL_DestroyTexture(g->brightnessOverlay); } // Set render scale mode const char *renderScaleQuality = "nearest"; switch ((ScaleMode)ConfigGetEnum(&gConfig, "Graphics.ScaleMode")) { case SCALE_MODE_NN: renderScaleQuality = "nearest"; break; case SCALE_MODE_BILINEAR: renderScaleQuality = "linear"; break; default: CASSERT(false, "unknown scale mode"); break; } LOG(LM_GFX, LL_DEBUG, "setting scale quality %s", renderScaleQuality); if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, renderScaleQuality)) { LOG(LM_GFX, LL_WARN, "cannot set render quality hint: %s", SDL_GetError()); } g->screen = CreateTexture( g->renderer, SDL_TEXTUREACCESS_STREAMING, Vec2iNew(w, h), SDL_BLENDMODE_BLEND, 255); if (g->screen == NULL) { return; } CFREE(g->buf); CCALLOC(g->buf, GraphicsGetMemSize(&g->cachedConfig)); g->bkg = CreateTexture( g->renderer, SDL_TEXTUREACCESS_STATIC, Vec2iNew(w, h), SDL_BLENDMODE_NONE, 255); if (g->bkg == NULL) { return; } } if (initBrightness) { if (!initRenderer && !initTextures) { SDL_DestroyTexture(g->brightnessOverlay); } const int brightness = ConfigGetInt(&gConfig, "Graphics.Brightness"); // Alpha is approximately 50% max const Uint8 alpha = (Uint8)(brightness > 0 ? brightness : -brightness) * 13; g->brightnessOverlay = CreateTexture( g->renderer, SDL_TEXTUREACCESS_STATIC, Vec2iNew(w, h), SDL_BLENDMODE_BLEND, alpha); if (g->brightnessOverlay == NULL) { return; } const color_t overlayColour = brightness > 0 ? colorWhite : colorBlack; DrawRectangle(g, Vec2iZero(), g->cachedConfig.Res, overlayColour, 0); SDL_UpdateTexture( g->brightnessOverlay, NULL, g->buf, g->cachedConfig.Res.x * sizeof(Uint32)); memset(g->buf, 0, GraphicsGetMemSize(&g->cachedConfig)); g->cachedConfig.Brightness = brightness; } g->IsInitialized = true; g->cachedConfig.Res.x = w; g->cachedConfig.Res.y = h; g->cachedConfig.RestartFlags = 0; }
int LoadCampaignOld(const char *filename, CampaignSettingOld *setting) { FILE *f = NULL; int32_t i; int err = 0; debug(D_NORMAL, "f: %s\n", filename); f = fopen(filename, "rb"); if (f == NULL) { err = -1; goto bail; } f_read32(f, &i, sizeof(i)); if (i != CAMPAIGN_MAGIC) { debug(D_NORMAL, "LoadCampaign - bad file!\n"); err = -1; goto bail; } f_read32(f, &i, sizeof(i)); if (i != CAMPAIGN_VERSION) { debug(D_NORMAL, "LoadCampaign - version mismatch!\n"); err = -1; goto bail; } f_read(f, setting->title, sizeof(setting->title)); f_read(f, setting->author, sizeof(setting->author)); f_read(f, setting->description, sizeof(setting->description)); f_read32(f, &setting->missionCount, sizeof(int32_t)); CCALLOC( setting->missions, setting->missionCount * sizeof *setting->missions); debug(D_NORMAL, "No. missions: %d\n", setting->missionCount); for (i = 0; i < setting->missionCount; i++) { load_mission(f, &setting->missions[i]); } f_read32(f, &setting->characterCount, sizeof(int32_t)); CCALLOC( setting->characters, setting->characterCount * sizeof *setting->characters); debug(D_NORMAL, "No. characters: %d\n", setting->characterCount); for (i = 0; i < setting->characterCount; i++) { load_character(f, &setting->characters[i]); } bail: if (f != NULL) { fclose(f); } return err; }
static TAction *AddActions(int count) { TAction *a; CCALLOC(a, sizeof(TAction) * (count + 1)); return a; }
int LoadCampaign( const char *filename, CampaignSetting *setting, int max_missions, int max_characters) { FILE *f = NULL; int i; int err = CAMPAIGN_OK; int numMissions = max_missions; int numCharacters = max_characters; debug(D_NORMAL, "f: %s\n", filename); f = fopen(filename, "rb"); if (f == NULL) { err = CAMPAIGN_BADPATH; goto bail; } f_read32(f, &i, sizeof(i)); if (i != CAMPAIGN_MAGIC) { debug(D_NORMAL, "LoadCampaign - bad file!\n"); err = CAMPAIGN_BADFILE; goto bail; } f_read32(f, &i, sizeof(i)); if (i != CAMPAIGN_VERSION) { debug(D_NORMAL, "LoadCampaign - version mismatch!\n"); err = CAMPAIGN_VERSIONMISMATCH; goto bail; } f_read(f, setting->title, sizeof(setting->title)); f_read(f, setting->author, sizeof(setting->author)); f_read(f, setting->description, sizeof(setting->description)); f_read32(f, &setting->missionCount, sizeof(setting->missionCount)); if (max_missions <= 0) { size_t size = setting->missionCount * sizeof(struct Mission); CCALLOC(setting->missions, size); numMissions = setting->missionCount; } else if (setting->missionCount < max_missions) { numMissions = setting->missionCount; } debug(D_NORMAL, "No. missions: %d\n", numMissions); for (i = 0; i < numMissions; i++) { load_mission(f, &setting->missions[i]); } f_read32(f, &setting->characterCount, sizeof(setting->characterCount)); if (max_characters <= 0) { size_t size = setting->characterCount * sizeof(TBadGuy); CCALLOC(setting->characters, size); numCharacters = setting->characterCount; } else if (setting->characterCount < max_characters) { numCharacters = setting->characterCount; } debug(D_NORMAL, "No. characters: %d\n", numCharacters); for (i = 0; i < numCharacters; i++) { load_character(f, &setting->characters[i]); } bail: if (f != NULL) { fclose(f); } return err; }