/** * @brief Clears the employees list for loaded and new games * @sa CL_ResetSinglePlayerData * @sa E_DeleteEmployee */ void E_ResetEmployees (void) { int i; Com_DPrintf(DEBUG_CLIENT, "E_ResetEmployees: Delete all employees\n"); for (i = EMPL_SOLDIER; i < MAX_EMPL; i++) LIST_Delete(&ccs.employees[i]); }
/** * @brief Closing operations for installations subsystem */ void INS_Shutdown (void) { LIST_Delete(&ccs.installations); #ifdef DEBUG Cmd_RemoveCommand("debug_listinstallation"); Cmd_RemoveCommand("debug_finishinstallation"); #endif }
static void testTeamDefsModelScriptData (void) { int i; linkedList_t *armourPaths = NULL; for (i = 0; i < csi.numTeamDefs; i++) { int j; const teamDef_t *teamDef = &csi.teamDef[i]; if (!teamDef->armour) continue; for (j = 0; j < csi.numODs; j++) { const objDef_t *od = INVSH_GetItemByIDX(j); if (!INV_IsArmour(od)) continue; /* not for this team */ if (!CHRSH_IsArmourUseableForTeam(od, teamDef)) continue; if (!LIST_ContainsString(armourPaths, od->armourPath)) LIST_AddString(&armourPaths, od->armourPath); } UFO_CU_ASSERT_TRUE_MSG(!LIST_IsEmpty(armourPaths), va("no armour definitions found for team %s - but armour is set to true", teamDef->id)); LIST_Foreach(armourPaths, char const, armourPath) { int l; for (l = NAME_NEUTRAL; l < NAME_LAST; l++) { /* no models for this gender */ if (!teamDef->numModels[l]) continue; CU_ASSERT_PTR_NOT_NULL_FATAL(teamDef->models[l]); for (linkedList_t const* list = teamDef->models[l]; list; list = list->next) { teamDef_t::model_t const& m = *static_cast<teamDef_t::model_t const*>(list->data); UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s/%s", m.path, m.body)), va("%s does not exist in models/%s (teamDef: %s)", m.body, m.path, teamDef->id)); UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s%s/%s", m.path, armourPath, m.body)), va("%s does not exist in models/%s%s (teamDef: %s)", m.body, m.path, armourPath, teamDef->id)); UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s/%s", m.path, m.head)), va("%s does not exist in models/%s (teamDef: %s)", m.head, m.path, teamDef->id)); UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s%s/%s", m.path, armourPath, m.head)), va("%s does not exist in models/%s%s (teamDef: %s)", m.head, m.path, armourPath, teamDef->id)); } } } LIST_Delete(&armourPaths); }
/** * @brief Display the popup_homebase * @param[in] aircraft Pointer to aircraft we want to change homebase. * @param[in] alwaysDisplay False if popup should be displayed only if at least one base is available. * @return true if popup is displayed. */ qboolean CL_DisplayHomebasePopup (aircraft_t *aircraft, qboolean alwaysDisplay) { int homebase; int numAvailableBases = 0; baseCapacities_t capacity; linkedList_t* popupListText = NULL; base_t *base; assert(aircraft); capacity = AIR_GetCapacityByAircraftWeight(aircraft); LIST_Delete(&popupListData); popupNum = 0; homebase = -1; base = NULL; while ((base = B_GetNext(base)) != NULL) { char text[MAX_VAR]; char const* msg; if (base == aircraft->homebase) { msg = _("current homebase of aircraft"); LIST_Add(&popupListData, (byte *)&INVALID_BASE, sizeof(int)); homebase = popupNum; } else { msg = AIR_CheckMoveIntoNewHomebase(aircraft, base, capacity); if (!msg) { msg = _("base can hold aircraft"); LIST_Add(&popupListData, (byte *)&base->idx, sizeof(int)); numAvailableBases++; } else { LIST_Add(&popupListData, (byte *)&INVALID_BASE, sizeof(int)); } } Com_sprintf(text, sizeof(text), "%s\t%s", base->name, msg); LIST_AddString(&popupListText, text); popupNum++; } if (alwaysDisplay || numAvailableBases > 0) { CL_GameTimeStop(); popupListNode = UI_PopupList(_("Change homebase of aircraft"), _("Base\tStatus"), popupListText, "change_homebase <lineselected>;"); VectorSet(popupListNode->selectedColor, 0.0, 0.78, 0.0); /**< Set color for selected entry. */ popupListNode->selectedColor[3] = 1.0; UI_TextNodeSelectLine(popupListNode, homebase); MAP_SelectAircraft(aircraft); return qtrue; } return qfalse; }
/** * @brief Parses music definitions for different situations * @note We have lists for geoscape, battlescape, main and aircombat */ void M_ParseMusic (const char* name, const char** text) { int i; if (Q_streq(name, "geoscape")) i = MUSIC_GEOSCAPE; else if (Q_streq(name, "battlescape")) i = MUSIC_BATTLESCAPE; else if (Q_streq(name, "aircombat")) i = MUSIC_AIRCOMBAT; else if (Q_streq(name, "main")) i = MUSIC_MAIN; else { Com_Printf("M_ParseMusic: Invalid music id '%s'!\n", name); linkedList_t* list; Com_ParseList(text, &list); LIST_Delete(&list); return; } /* get it's body */ linkedList_t* list; if (!Com_ParseList(text, &list)) { Com_Error(ERR_DROP, "M_ParseMusic: error while reading music \"%s\"", name); } for (linkedList_t* element = list; element != nullptr; element = element->next) { if (musicArrayLength[i] >= MUSIC_MAX_ENTRIES) { Com_Printf("M_ParseMusic: Too many music entries for category: '%s'!\n", name); break; } musicArrays[i][musicArrayLength[i]] = Mem_PoolStrDup((char*)element->data, cl_genericPool, 0); musicArrayLength[i]++; } LIST_Delete(&list); }
static void UI_TextNodeGenerateLineSplit (uiNode_t* node) { const char* data; int bufferSize = 1024; char* buffer = Mem_AllocTypeN(char, bufferSize); LIST_Delete(&EXTRADATA(node).lineSplit); if (node->text != nullptr) data = UI_GetReferenceString(node, node->text); else if (EXTRADATA(node).super.dataID != TEXT_NULL) { const uiSharedData_t* shared; shared = &ui_global.sharedData[EXTRADATA(node).super.dataID]; switch (shared->type) { case UI_SHARED_TEXT: data = UI_GetText(EXTRADATA(node).super.dataID); break; case UI_SHARED_LINKEDLISTTEXT: return; default: return; } } else return; data = CL_Translate(data); while (data[0] != '\0') { const char* next = strchr(data, '\n'); int lineSize; if (next == nullptr) lineSize = strlen(data); else lineSize = next - data; if (lineSize + 1 > bufferSize) { bufferSize = lineSize + 1; Mem_Free(buffer); buffer = Mem_AllocTypeN(char, bufferSize); } Q_strncpyz(buffer, data, lineSize + 1); LIST_AddString(&EXTRADATA(node).lineSplit, buffer); if (next == nullptr) break; data = next + 1; }
/** * @brief Console function to push a window onto the window stack * @sa UI_PushWindow */ static void UI_PushWindow_f (void) { linkedList_t *params = NULL; int i; if (Cmd_Argc() == 0) { Com_Printf("Usage: %s <name> <params>\n", Cmd_Argv(0)); return; } for (i = 2; i < Cmd_Argc(); i++) { LIST_AddString(¶ms, Cmd_Argv(i)); } UI_PushWindow(Cmd_Argv(1), NULL, params); LIST_Delete(¶ms); }
/** * @brief unittest to check well formed list */ TEST_F(ParserTest, ParserListOk) { const char* string = " ( aaa \n \"bbb\" \t ccc \n \n ) "; const char* cursor = string; linkedList_t* list; ASSERT_TRUE(Com_ParseList(&cursor, &list)) << "List parsing failed"; ASSERT_EQ(LIST_Count(list), 3); ASSERT_STREQ(static_cast<const char*>(list->data), "aaa"); ASSERT_STREQ(static_cast<const char*>(list->next->data), "bbb"); ASSERT_STREQ(static_cast<const char*>(list->next->next->data), "ccc"); LIST_Delete(&list); }
/** * @brief Set Harvest mission, and go to mission pos. * @note Harvesting attack mission -- Stage 1 * @todo Remove me when CP_XVIMissionGo will be implemented * This function should take a location close to an XVI infection point * see gameplay proposal on wiki */ void CP_HarvestMissionGo (mission_t *mission) { const nation_t *nation; mission->stage = STAGE_MISSION_GOTO; /* Choose a map */ if (CP_ChooseMap(mission, NULL)) { int counter; linkedList_t *nationList = NULL; const qboolean nationTest = CP_ChooseNation(mission, &nationList); for (counter = 0; counter < MAX_POS_LOOP; counter++) { if (!CP_GetRandomPosOnGeoscapeWithParameters(mission->pos, mission->mapDef->terrains, mission->mapDef->cultures, mission->mapDef->populations, nationTest ? nationList : NULL)) continue; if (MAP_PositionCloseToBase(mission->pos)) continue; mission->posAssigned = qtrue; break; } if (counter >= MAX_POS_LOOP) { Com_Printf("CP_HarvestMissionGo: Error, could not set position.\n"); CP_MissionRemove(mission); return; } LIST_Delete(&nationList); } else { Com_Printf("CP_HarvestMissionGo: No map found, remove mission.\n"); CP_MissionRemove(mission); return; } nation = MAP_GetNation(mission->pos); if (nation) { Com_sprintf(mission->location, sizeof(mission->location), "%s", _(nation->name)); } else { Com_sprintf(mission->location, sizeof(mission->location), "%s", _("No nation")); } if (mission->ufo) { CP_MissionDisableTimeLimit(mission); UFO_SendToDestination(mission->ufo, mission->pos); } else { /* Go to next stage on next frame */ mission->finalDate = ccs.date; } }
/** * @brief Reset a shared data. Type became NONE and value became NULL */ void UI_ResetData (int dataId) { assert(dataId < UI_MAX_DATAID); assert(dataId >= 0); switch (ui_global.sharedData[dataId].type) { case UI_SHARED_LINKEDLISTTEXT: LIST_Delete(&ui_global.sharedData[dataId].data.linkedListText); break; case UI_SHARED_OPTION: if (_Mem_AllocatedInPool(com_genericPool, ui_global.sharedData[dataId].data.option)) { UI_DeleteOption(ui_global.sharedData[dataId].data.option); } break; default: break; } ui_global.sharedData[dataId].type = UI_SHARED_NONE; ui_global.sharedData[dataId].data.text = NULL; ui_global.sharedData[dataId].versionId++; }
/** * @brief Return a "hired" ugv-employee pointer of a given ugv-type in a given base. * @param[in] base Which base the ugv should be searched in.c * @param[in] ugvType What type of robot we want. * @return employee_t pointer on success or NULL on error. * @sa E_GetUnhiredRobot */ employee_t* E_GetHiredRobot (const base_t* const base, const ugv_t *ugvType) { linkedList_t *hiredEmployees = NULL; employee_t *employee; E_GetHiredEmployees(base, EMPL_ROBOT, &hiredEmployees); LIST_Foreach(hiredEmployees, employee_t, employee) { if ((employee->ugv == ugvType || !ugvType) /* If no type was given we return the first ugv we find. */ && E_IsInBase(employee, base)) { /* It has to be in the defined base. */ assert(E_IsHired(employee)); break; } } LIST_Delete(&hiredEmployees); if (!employee) Com_DPrintf(DEBUG_CLIENT, "Could not get unhired ugv/robot.\n"); return employee; }
/** * @brief Return a list of hired employees in the given base of a given type * @param[in] base Which base the employee should be searched in. If NULL is given employees in all bases will be listed. * @param[in] type Which employee type to search for. * @param[out] hiredEmployees Linked list of hired employees in the base. * @return Number of hired employees in the base that are currently not on a transfer. Or @c -1 in case of an error. */ int E_GetHiredEmployees (const base_t* const base, employeeType_t type, linkedList_t **hiredEmployees) { employee_t *employee; if (type >= MAX_EMPL) { Com_Printf("E_GetHiredEmployees: Unknown EmployeeType: %i\n", type); *hiredEmployees = NULL; return -1; } LIST_Delete(hiredEmployees); E_Foreach(type, employee) { if (!E_IsHired(employee)) continue; if (!employee->transfer && (!base || E_IsInBase(employee, base))) { LIST_AddPointer(hiredEmployees, employee); } } if (hiredEmployees == NULL) return 0; return LIST_Count(*hiredEmployees); }
/** * @brief Reads the sequence values from given text-pointer * @sa CL_ParseClientData */ void CL_ParseSequence (const char *name, const char **text) { const char *errhead = "CL_ParseSequence: unexpected end of file (sequence "; sequence_t *sp; const char *token; int i; /* search for sequences with same name */ for (i = 0; i < numSequences; i++) if (Q_streq(name, sequences[i].name)) break; if (i < numSequences) { Com_Printf("CL_ParseSequence: sequence def \"%s\" with same name found, second ignored\n", name); return; } /* initialize the sequence */ if (numSequences >= MAX_SEQUENCES) Com_Error(ERR_FATAL, "Too many sequences"); sp = &sequences[numSequences++]; OBJZERO(*sp); Q_strncpyz(sp->name, name, sizeof(sp->name)); sp->start = numSeqCmds; /* get it's body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("CL_ParseSequence: sequence def \"%s\" without body ignored\n", name); numSequences--; return; } do { token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* check for commands */ int i = CL_FindSequenceCommand(token); if (i != -1) { int maxLength = MAX_DATA_LENGTH; char *data; seqCmd_t *sc; /* found a command */ token = Com_EParse(text, errhead, name); if (!*text) return; if (numSeqCmds >= MAX_SEQCMDS) Com_Error(ERR_FATAL, "Too many sequence commands for %s", name); /* init seqCmd */ if (seqCmds == NULL) seqCmds = Mem_PoolAllocTypeN(seqCmd_t, MAX_SEQCMDS, cl_genericPool); sc = &seqCmds[numSeqCmds++]; OBJZERO(*sc); sc->handler = seqCmdFunc[i]; sp->length++; /* copy name */ Q_strncpyz(sc->name, token, sizeof(sc->name)); /* read data */ token = Com_EParse(text, errhead, name); if (!*text) return; if (*token == '{') { // TODO depth is useless IMHO (bayo) int depth = 1; data = &sc->data[0]; while (depth) { if (maxLength <= 0) { Com_Printf("Too much data for sequence %s", sc->name); break; } token = Com_EParse(text, errhead, name); if (!*text) return; if (*token == '{') depth++; else if (*token == '}') depth--; if (depth) { Q_strncpyz(data, token, maxLength); data += strlen(token) + 1; maxLength -= (strlen(token) + 1); } } } else if (*token == '(') { linkedList_t *list; Com_UnParseLastToken(); if (!Com_ParseList(text, &list)) { Com_Error(ERR_DROP, "CL_ParseSequence: error while reading list (sequence \"%s\")", name); } data = &sc->data[0]; for (linkedList_t *element = list; element != NULL; element = element->next) { if (maxLength <= 0) { Com_Printf("Too much data for sequence %s", sc->name); break; } const char* v = (char*)element->data; Q_strncpyz(data, v, maxLength); data += strlen(v) + 1; maxLength -= (strlen(v) + 1); } LIST_Delete(&list); } else { Com_UnParseLastToken(); } } else { Com_Printf("CL_ParseSequence: unknown command \"%s\" ignored (sequence %s)\n", token, name); Com_EParse(text, errhead, name); } } while (*text); }
static void testTeamDefsModelScriptData (void) { int i; linkedList_t *armourPaths = NULL; for (i = 0; i < csi.numTeamDefs; i++) { int j; const teamDef_t *teamDef = &csi.teamDef[i]; if (!teamDef->armour) continue; for (j = 0; j < csi.numODs; j++) { const objDef_t *od = INVSH_GetItemByIDX(j); if (!INV_IsArmour(od)) continue; /* not for this team */ if (!CHRSH_IsArmourUseableForTeam(od, teamDef)) continue; if (!LIST_ContainsString(armourPaths, od->armourPath)) LIST_AddString(&armourPaths, od->armourPath); } UFO_CU_ASSERT_TRUE_MSG(!LIST_IsEmpty(armourPaths), va("no armour definitions found for team %s - but armour is set to true", teamDef->id)); LIST_Foreach(armourPaths, char const, armourPath) { nametypes_t l; for (l = NAME_NEUTRAL; l < NAME_LAST; l++) { linkedList_t *list = teamDef->models[l]; int k; /* no models for this gender */ if (!teamDef->numModels[l]) continue; CU_ASSERT_PTR_NOT_NULL(list); for (k = 0; k < teamDef->numModels[l]; k++) { const char *path; CU_ASSERT_PTR_NOT_NULL_FATAL(list); path = (const char*)list->data; /* body */ list = list->next; CU_ASSERT_PTR_NOT_NULL_FATAL(list); UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s/%s", path, list->data)), va("%s does not exist in models/%s (teamDef: %s)", list->data, path, teamDef->id)); UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s%s/%s", path, armourPath, list->data)), va("%s does not exist in models/%s%s (teamDef: %s)", list->data, path, armourPath, teamDef->id)); list = list->next; CU_ASSERT_PTR_NOT_NULL_FATAL(list); /* head */ UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s/%s", path, list->data)), va("%s does not exist in models/%s (teamDef: %s)", list->data, path, teamDef->id)); UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s%s/%s", path, armourPath, list->data)), va("%s does not exist in models/%s%s (teamDef: %s)", list->data, path, armourPath, teamDef->id)); /* skip skin */ /** @todo check that the skin is valid for the given model */ list = list->next; CU_ASSERT_PTR_NOT_NULL_FATAL(list); /* new path */ list = list->next; } } } LIST_Delete(&armourPaths); }
static inline void UI_ExecuteCallAction (const uiAction_t* action, const uiCallContext_t *context) { uiNode_t* callNode = NULL; uiAction_t* param; uiAction_t* left = action->d.nonTerminal.left; uiCallContext_t newContext; const value_t* callProperty = NULL; const char* path = left->d.terminal.d1.constString; if (left->type == EA_VALUE_PATHPROPERTY || left->type == EA_VALUE_PATHNODE) path = left->d.terminal.d1.constString; else if (left->type == EA_VALUE_PATHPROPERTY_WITHINJECTION || left->type == EA_VALUE_PATHNODE_WITHINJECTION) path = UI_GenInjectedString(left->d.terminal.d1.constString, false, context); UI_ReadNodePath(path, context->source, &callNode, &callProperty); if (callNode == NULL) { Com_Printf("UI_ExecuteCallAction: Node from path \"%s\" not found (relative to \"%s\").\n", path, UI_GetPath(context->source)); return; } if (callProperty != NULL && callProperty->type != V_UI_ACTION && callProperty->type != V_UI_NODEMETHOD) { Com_Printf("UI_ExecuteCallAction: Call operand %d unsupported. (%s)\n", callProperty->type, UI_GetPath(callNode)); return; } newContext.source = callNode; newContext.params = NULL; newContext.paramNumber = 0; newContext.varNumber = 0; newContext.varPosition = context->varPosition + context->varNumber; if (action->type == EA_LISTENER) { newContext.useCmdParam = context->useCmdParam; if (!newContext.useCmdParam) { linkedList_t *p = context->params; while (p) { const char* value = (char*) p->data; LIST_AddString(&newContext.params, value); newContext.paramNumber++; p = p->next; } } } else { newContext.useCmdParam = false; param = action->d.nonTerminal.right; while (param) { const char* value; value = UI_GetStringFromExpression(param, context); LIST_AddString(&newContext.params, value); newContext.paramNumber++; param = param->next; } } if (callProperty == NULL || callProperty->type == V_UI_ACTION) { uiAction_t const* const actionsRef = callProperty ? Com_GetValue<uiAction_t*>(callNode, callProperty) : callNode->onClick; UI_ExecuteActions(actionsRef, &newContext); } else if (callProperty->type == V_UI_NODEMETHOD) { uiNodeMethod_t func = (uiNodeMethod_t) callProperty->ofs; func(callNode, &newContext); } else { /* unreachable, already checked few line before */ assert(false); } LIST_Delete(&newContext.params); }
/** * @sa CL_ParseScriptFirst */ static void CP_ParseAlienTeam (const char *name, const char **text) { const char *errhead = "CP_ParseAlienTeam: unexpected end of file (alienteam "; const char *token; int i; alienTeamCategory_t *alienCategory; /* get it's body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("CP_ParseAlienTeam: alien team category \"%s\" without body ignored\n", name); return; } if (ccs.numAlienCategories >= ALIENCATEGORY_MAX) { Com_Printf("CP_ParseAlienTeam: maximum number of alien team category reached (%i)\n", ALIENCATEGORY_MAX); return; } /* search for category with same name */ for (i = 0; i < ccs.numAlienCategories; i++) if (Q_streq(name, ccs.alienCategories[i].id)) break; if (i < ccs.numAlienCategories) { Com_Printf("CP_ParseAlienTeam: alien category def \"%s\" with same name found, second ignored\n", name); return; } alienCategory = &ccs.alienCategories[ccs.numAlienCategories++]; Q_strncpyz(alienCategory->id, name, sizeof(alienCategory->id)); do { token = cgi->Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; if (Q_streq(token, "equipment")) { linkedList_t **list = &alienCategory->equipment; if (!Com_ParseList(text, list)) { cgi->Com_Error(ERR_DROP, "CL_ParseAlienTeam: \"%s\" Error while parsing equipment list", name); } } else if (Q_streq(token, "category")) { linkedList_t *list; if (!Com_ParseList(text, &list)) { cgi->Com_Error(ERR_DROP, "CL_ParseAlienTeam: \"%s\" Error while parsing category list", name); } for (linkedList_t *element = list; element != NULL; element = element->next) { alienCategory->missionCategories[alienCategory->numMissionCategories] = CP_GetAlienMissionTypeByID((char*)element->data); if (alienCategory->missionCategories[alienCategory->numMissionCategories] == INTERESTCATEGORY_NONE) Com_Printf("CP_ParseAlienTeam: alien team category \"%s\" is used with no mission category. It won't be used in game.\n", name); alienCategory->numMissionCategories++; } LIST_Delete(&list); } else if (Q_streq(token, "teaminterest")) { alienTeamGroup_t *group; token = cgi->Com_EParse(text, errhead, name); if (!*text || *token != '{') { Com_Printf("CP_ParseAlienTeam: alien team \"%s\" has team with no opening brace\n", name); break; } if (alienCategory->numAlienTeamGroups >= MAX_ALIEN_GROUP_PER_CATEGORY) { Com_Printf("CP_ParseAlienTeam: maximum number of alien team reached (%i) in category \"%s\"\n", MAX_ALIEN_GROUP_PER_CATEGORY, name); break; } group = &alienCategory->alienTeamGroups[alienCategory->numAlienTeamGroups]; group->idx = alienCategory->numAlienTeamGroups; group->categoryIdx = alienCategory - ccs.alienCategories; alienCategory->numAlienTeamGroups++; do { token = cgi->Com_EParse(text, errhead, name); if (!Com_ParseBlockToken(name, text, group, alien_group_vals, cp_campaignPool, token)) { const teamDef_t *teamDef; if (!*text || *token == '}') break; if (Q_streq(token, "team")) { linkedList_t *list; if (!Com_ParseList(text, &list)) { cgi->Com_Error(ERR_DROP, "CL_ParseAlienTeam: \"%s\" Error while parsing team list", name); } for (linkedList_t *element = list; element != NULL; element = element->next) { if (group->numAlienTeams >= MAX_TEAMS_PER_MISSION) cgi->Com_Error(ERR_DROP, "CL_ParseAlienTeam: MAX_TEAMS_PER_MISSION hit"); teamDef = cgi->Com_GetTeamDefinitionByID((char*)element->data); if (teamDef) group->alienTeams[group->numAlienTeams++] = teamDef; } LIST_Delete(&list); } else { cgi->Com_Error(ERR_DROP, "CL_ParseAlienTeam: Unknown token \"%s\"\n", token); } } } while (*text); } else { Com_Printf("CP_ParseAlienTeam: unknown token \"%s\" ignored (category %s)\n", token, name); continue; } } while (*text); if (LIST_IsEmpty(alienCategory->equipment)) Sys_Error("alien category equipment list is empty"); }
/** * @brief Start Base Attack. * @note Base attack mission -- Stage 2 */ void CP_BaseAttackStartMission (mission_t *mission) { base_t *base = mission->data.base; linkedList_t *hiredSoldiersInBase = NULL; employee_t *employee; assert(base); mission->stage = STAGE_BASE_ATTACK; CP_MissionDisableTimeLimit(mission); if (mission->ufo) { /* ufo becomes invisible on geoscape, but don't remove it from ufo global array (may reappear)*/ CP_UFORemoveFromGeoscape(mission, qfalse); } /* we always need at least one command centre in the base - because the * phalanx soldiers have their starting positions here. * There should also always be an entrance - the aliens start there * but we don't need to check that as entrance can't be destroyed */ if (!B_GetNumberOfBuildingsInBaseByBuildingType(base, B_COMMAND)) { /** @todo handle command centre properly */ Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no Command Center: it can't defend itself. Destroy base.\n", base->name); CP_BaseAttackMissionDestroyBase(mission); return; } base->baseStatus = BASE_UNDER_ATTACK; ccs.campaignStats.basesAttacked++; #if 0 /** @todo implement onattack: add it to basemanagement.ufo and implement functions */ if (base->onAttack[0] != '\0') /* execute next frame */ Cbuf_AddText(va("%s %i", base->onAttack, base->id)); #endif MAP_SelectMission(mission); mission->active = qtrue; ccs.mapAction = MA_BASEATTACK; Com_DPrintf(DEBUG_CLIENT, "Base attack: %s at %.0f:%.0f\n", mission->id, mission->pos[0], mission->pos[1]); /** @todo EMPL_ROBOT */ E_GetHiredEmployees(base, EMPL_SOLDIER, &hiredSoldiersInBase); /* Fill the fake aircraft */ OBJZERO(baseAttackFakeAircraft); baseAttackFakeAircraft.homebase = base; /* needed for transfer of alien corpses */ VectorCopy(base->pos, baseAttackFakeAircraft.pos); #if 0 /** @todo active this once more than 8 soldiers are working */ /* needed to spawn soldiers on map */ baseAttackFakeAircraft.maxTeamSize = LIST_Count(hiredSoldiersInBase); #else baseAttackFakeAircraft.maxTeamSize = MAX_ACTIVETEAM; #endif if (!hiredSoldiersInBase) { Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no soldiers: it can't defend itself. Destroy base.\n", base->name); CP_BaseAttackMissionDestroyBase(mission); return; } LIST_Foreach(hiredSoldiersInBase, employee_t, employee) { if (E_IsAwayFromBase(employee)) continue; AIR_AddToAircraftTeam(&baseAttackFakeAircraft, employee); } if (AIR_GetTeamSize(&baseAttackFakeAircraft) == 0) { Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no soldiers at home: it can't defend itself. Destroy base.\n", base->name); CP_BaseAttackMissionDestroyBase(mission); return; } #if 0 /** @todo active this once more than 8 soldiers are working */ /* all soldiers in the base should get used */ baseAttackFakeAircraft.maxTeamSize = AIR_GetTeamSize(&baseAttackFakeAircraft); #endif LIST_Delete(&hiredSoldiersInBase); base->aircraftCurrent = &baseAttackFakeAircraft; MAP_SetMissionAircraft(&baseAttackFakeAircraft); /** @todo remove me - this is not needed because we are using the base->aircraftCurrent * pointer for resolving the aircraft - only CL_GameAutoGo needs this */ MAP_SetInterceptorAircraft(&baseAttackFakeAircraft); /* needed for updating soldier stats sa CL_UpdateCharacterStats*/ B_SetCurrentSelectedBase(base); /* needed for equipment menu */ Com_sprintf(popupText, sizeof(popupText), _("Base '%s' is under attack! What to do ?"), base->name); UI_RegisterText(TEXT_POPUP, popupText); CL_GameTimeStop(); UI_PushWindow("popup_baseattack", NULL, NULL); }
static inline void UI_ExecuteCallAction (const uiAction_t* action, const uiCallContext_t* context) { uiNode_t* callNode = nullptr; uiAction_t* param; uiAction_t* left = action->d.nonTerminal.left; uiCallContext_t newContext; const value_t* callProperty = nullptr; value_t luaMethod; const char* path = left->d.terminal.d1.constString; // clear luaMethod structure before using it memset(&luaMethod, 0, sizeof(luaMethod)); if (left->type == EA_VALUE_PATHPROPERTY || left->type == EA_VALUE_PATHNODE) path = left->d.terminal.d1.constString; else if (left->type == EA_VALUE_PATHPROPERTY_WITHINJECTION || left->type == EA_VALUE_PATHNODE_WITHINJECTION) path = UI_GenInjectedString(left->d.terminal.d1.constString, false, context); UI_ReadNodePath(path, context->source, context->tagNode, &callNode, &callProperty, &luaMethod); if ((callNode == nullptr) && (!luaMethod.type)) { Com_Printf("UI_ExecuteCallAction: Node from path \"%s\" not found (relative to \"%s\").\n", path, UI_GetPath(context->source)); return; } if (callProperty != nullptr && callProperty->type != V_UI_ACTION && callProperty->type != V_UI_NODEMETHOD && callProperty->type != V_UI_NODEMETHOD_LUA) { Com_Printf("UI_ExecuteCallAction: Call operand %d unsupported. (%s)\n", callProperty->type, UI_GetPath(callNode)); return; } newContext.source = callNode; newContext.params = nullptr; newContext.paramNumber = 0; newContext.varNumber = 0; newContext.varPosition = context->varPosition + context->varNumber; newContext.breakLoop = false; if (action->type == EA_LISTENER) { newContext.useCmdParam = context->useCmdParam; if (!newContext.useCmdParam) { linkedList_t* p = context->params; while (p) { const char* value = (char*) p->data; LIST_AddString(&newContext.params, value); newContext.paramNumber++; p = p->next; } } } else { newContext.useCmdParam = false; param = action->d.nonTerminal.right; while (param) { const char* value; value = UI_GetStringFromExpression(param, context); LIST_AddString(&newContext.params, value); newContext.paramNumber++; param = param->next; } } if (luaMethod.type == V_UI_NODEMETHOD_LUA) { UI_ExecuteLuaMethod(callNode, luaMethod.ofs, newContext.params, newContext.paramNumber); Mem_Free(const_cast<char*>(luaMethod.string)); } else if (callProperty == nullptr || callProperty->type == V_UI_ACTION) { uiAction_t const* const actionsRef = callProperty ? Com_GetValue<uiAction_t*>(callNode, callProperty) : callNode->onClick; if (actionsRef) UI_ExecuteActions(actionsRef, &newContext); if (callNode->lua_onClick != LUA_NOREF) UI_ExecuteLuaMethod(callNode, callNode->lua_onClick, newContext.params, newContext.paramNumber); } else if (callProperty->type == V_UI_NODEMETHOD) { uiNodeMethod_t func = (uiNodeMethod_t) callProperty->ofs; func(callNode, &newContext); } else { /* unreachable, already checked few line before */ assert(false); } LIST_Delete(&newContext.params); }
/** * @brief Make sure, that the linked list is freed with every new game * @sa CP_ResetCampaignData */ void CP_FreeDynamicEventMail (void) { /* the pointers are not freed, this is done with the * pool clear in CP_ResetCampaignData */ LIST_Delete(&eventMails); }
/** * @brief Parse all language definitions from the script files */ void CL_ParseLanguages (const char* name, const char** text) { const char* errhead = "CL_ParseLanguages: unexpected end of file (language "; const char* token; if (!*text) { Com_Printf("CL_ParseLanguages: language without body ignored (%s)\n", name); return; } token = Com_EParse(text, errhead, name); if (!*text || *token != '{') { Com_Printf("CL_ParseLanguages: language without body ignored (%s)\n", name); return; } language_t* const language = Mem_PoolAllocType(language_t, cl_genericPool); language->localeID = Mem_PoolStrDup(name, cl_genericPool, 0); language->localeString = ""; language->nativeString = ""; language->localeMapping = nullptr; do { /* get the name type */ token = Com_EParse(text, errhead, name); if (!*text || *token == '}') break; /* inner locale id definition */ if (Q_streq(token, "code")) { linkedList_t* list; if (!Com_ParseList(text, &list)) { Com_Error(ERR_DROP, "CL_ParseLanguages: error while reading language codes \"%s\"", name); } for (linkedList_t* element = list; element != nullptr; element = element->next) { localeMapping_t* const mapping = Mem_PoolAllocType(localeMapping_t, cl_genericPool); mapping->localeMapping = Mem_PoolStrDup((char*)element->data, cl_genericPool, 0); /* link it in */ mapping->next = language->localeMapping; language->localeMapping = mapping; } LIST_Delete(&list); } else if (Q_streq(token, "name")) { token = Com_EParse(text, errhead, name); if (!*text || *token == '}') Com_Error(ERR_FATAL, "CL_ParseLanguages: Name expected for language \"%s\".\n", name); if (*token != '_') { Com_Printf("CL_ParseLanguages: language: '%s' - not marked translatable (%s)\n", name, token); } language->localeString = Mem_PoolStrDup(token, cl_genericPool, 0); } else if (Q_streq(token, "native")) { token = Com_EParse(text, errhead, name); if (!*text || *token == '}') Com_Error(ERR_FATAL, "CL_ParseLanguages: Native expected for language \"%s\".\n", name); language->nativeString = Mem_PoolStrDup(token, cl_genericPool, 0); } } while (*text); language->next = languageList; languageList = language; languageCount++; }