/** * @brief Replace injection identifiers (e.g. <eventParam>) by a value * @note The injection identifier can be every node value - e.g. <image> or <width>. * It's also possible to do something like * @code * cmd "set someCvar <min>/<max>" * @endcode */ const char* UI_GenInjectedString (const char* input, qboolean addNewLine, const uiCallContext_t *context) { static char cmd[256]; int length = sizeof(cmd) - (addNewLine ? 2 : 1); static char propertyName[MAX_VAR]; const char *cin = input; char *cout = cmd; while (length && cin[0] != '\0') { if (cin[0] == '<') { /* read propertyName between '<' and '>' */ const char *next = UI_GenCommandReadProperty(cin, propertyName, sizeof(propertyName)); if (next) { /* cvar injection */ if (Q_strstart(propertyName, "cvar:")) { const cvar_t *cvar = Cvar_Get(propertyName + 5, "", 0, NULL); const int l = snprintf(cout, length, "%s", cvar->string); cout += l; cin = next; length -= l; continue; } else if (Q_strstart(propertyName, "node:")) { const char *path = propertyName + 5; uiNode_t *node; const value_t *property; const char* string; int l; UI_ReadNodePath(path, context->source, &node, &property); if (!node) { Com_Printf("UI_GenInjectedString: Node '%s' wasn't found; '' returned\n", path); #ifdef DEBUG Com_Printf("UI_GenInjectedString: Path relative to '%s'\n", UI_GetPath(context->source)); #endif string = ""; } else if (!property) { Com_Printf("UI_GenInjectedString: Property '%s' wasn't found; '' returned\n", path); string = ""; } else { string = UI_GetStringFromNodeProperty(node, property); if (string == NULL) { Com_Printf("UI_GenInjectedString: String getter for '%s' property do not exists; '' injected\n", path); string = ""; } } l = snprintf(cout, length, "%s", string); cout += l; cin = next; length -= l; continue; /* source path injection */ } else if (Q_strstart(propertyName, "path:")) { if (context->source) { const char *command = propertyName + 5; const uiNode_t *node = NULL; if (Q_streq(command, "root")) node = context->source->root; else if (Q_streq(command, "this")) node = context->source; else if (Q_streq(command, "parent")) node = context->source->parent; else Com_Printf("UI_GenCommand: Command '%s' for path injection unknown\n", command); if (node) { const int l = snprintf(cout, length, "%s", UI_GetPath(node)); cout += l; cin = next; length -= l; continue; } } /* no prefix */ } else { /* source property injection */ if (context->source) { /* find property definition */ const value_t *property = UI_GetPropertyFromBehaviour(context->source->behaviour, propertyName); if (property) { const char* value; int l; /* inject the property value */ value = UI_GetStringFromNodeProperty(context->source, property); if (value == NULL) value = ""; l = snprintf(cout, length, "%s", value); cout += l; cin = next; length -= l; continue; } } /* param injection */ if (UI_GetParamNumber(context) != 0) { int arg; const int checked = sscanf(propertyName, "%d", &arg); if (checked == 1 && arg >= 1 && arg <= UI_GetParamNumber(context)) { const int l = snprintf(cout, length, "%s", UI_GetParam(context, arg)); cout += l; cin = next; length -= l; continue; } } } } } *cout++ = *cin++; length--; } /* is buffer too small? */ assert(cin[0] == '\0'); if (addNewLine) *cout++ = '\n'; *cout++ = '\0'; /* copy the result into a free va slot */ return va("%s", cmd); }
/** * @brief Copies an entry from the installation description file into the list of installation templates. * @note Parses one "installation" entry in the installation.ufo file and writes * it into the next free entry in installationTemplates. * @param[in] name Unique test-id of a installationTemplate_t. * @param[in] text the rest of the script file that is tokenized here */ void INS_ParseInstallations (const char *name, const char **text) { installationTemplate_t *installation; const char *errhead = "INS_ParseInstallations: unexpected end of file (names "; const char *token; int i; /* get id list body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("INS_ParseInstallations: installation \"%s\" without body ignored\n", name); return; } if (!name) { Com_Printf("INS_ParseInstallations: installation name not specified.\n"); return; } if (ccs.numInstallationTemplates >= MAX_INSTALLATION_TEMPLATES) { Com_Printf("INS_ParseInstallations: too many installation templates\n"); ccs.numInstallationTemplates = MAX_INSTALLATION_TEMPLATES; /* just in case it's bigger. */ return; } for (i = 0; i < ccs.numInstallationTemplates; i++) { if (Q_streq(ccs.installationTemplates[i].name, name)) { Com_Printf("INS_ParseInstallations: Second installation with same name found (%s) - second ignored\n", name); return; } } /* new entry */ installation = &ccs.installationTemplates[ccs.numInstallationTemplates]; OBJZERO(*installation); installation->id = Mem_PoolStrDup(name, cp_campaignPool, 0); Com_DPrintf(DEBUG_CLIENT, "...found installation %s\n", installation->id); ccs.numInstallationTemplates++; do { /* get the name type */ token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* check for some standard values */ if (!Com_ParseBlockToken(name, text, installation, installation_vals, cp_campaignPool, token)) { /* other values */ if (Q_streq(token, "cost")) { char cvarname[MAX_VAR] = "mn_installation_"; Q_strcat(cvarname, installation->id, sizeof(cvarname)); Q_strcat(cvarname, "_cost", sizeof(cvarname)); token = Com_EParse(text, errhead, name); if (!*text) return; installation->cost = atoi(token); Cvar_Set(cvarname, va(_("%d c"), atoi(token))); } else if (Q_streq(token, "buildtime")) { char cvarname[MAX_VAR]; token = Com_EParse(text, errhead, name); if (!*text) return; installation->buildTime = atoi(token); Com_sprintf(cvarname, sizeof(cvarname), "mn_installation_%s_buildtime", installation->id); Cvar_Set(cvarname, va(ngettext("%d day", "%d days", atoi(token)), atoi(token))); } } } while (*text); }
/** * @brief This test cycles through the list of map definitions found in the maps.ufo script * and builds each map with each ufo and every assembly for all valid seeds. * In other words: this a FULL test to check if some seed causes problems in any of the * possible combinations, so it should not be run on the buildserver on a daily basis. */ TEST_F(MapDefMassRMATest, DISABLED_MapDefsMassRMA) { /** You can test a certain assembly by passing "-Dmapdef-id=assembly" to testall. */ const char* filterId = TEST_GetStringProperty("mapdef-id"); const mapDef_t* md; int mapCount = 0; ASSERT_TRUE(csi.numMDs > 0); MapDef_Foreach(md) { if (md->mapTheme[0] == '.') continue; if (filterId && !Q_streq(filterId, md->id)) continue; if (++mapCount <= 0) /* change 0 to n to skip the first n assemblies */ continue; { char* p = md->mapTheme; if (*p == '+') p++; else continue; const char* asmName = (const char*)LIST_GetByIdx(md->params, 0); Com_Printf("\nMap: %s Assembly: %s AssNr: %i\n", p, asmName, mapCount); sv_threads->integer = 0; /* This is tricky. Some maps don't have any ufo on them and thus in the mapdef. * That would cause a LIST_Foreach macro to never run it's body. That's why these * for-loops seem to have two termination conditions. In fact, we have to manually * exit the for-loops if we ran it just once (without ufos nor dropships). */ bool didItOnce = false; linkedList_t* iterDrop; for (iterDrop = md->aircraft; iterDrop || !didItOnce; iterDrop = iterDrop->next) { const char* craft = nullptr; if (iterDrop) craft = (const char*) (iterDrop->data); if (craft) Cvar_Set("rm_drop", "%s", Com_GetRandomMapAssemblyNameForCraft(craft)); else Cvar_Set("rm_drop", "+craft_drop_firebird"); linkedList_t* iterUfo; for (iterUfo = md->ufos; iterUfo || !didItOnce; iterUfo = iterUfo->next) { const char* ufo = nullptr; if (iterUfo) ufo = (const char*) (iterUfo->data); if (ufo) Cvar_Set("rm_ufo", "%s", Com_GetRandomMapAssemblyNameForCraft(ufo)); else Cvar_Set("rm_ufo", "+craft_ufo_scout"); Com_Printf("\nDrop: %s Ufo: %s", craft, ufo); Com_Printf("\nSeed:"); for (int i = 0; i < RMA_HIGHEST_SUPPORTED_SEED; i++) { asmName = nullptr; srand(i); long time = Sys_Milliseconds(); Com_Printf(" %i", i); #if 0 typedef struct skip_info { int seed; char const* map; char const* params; char const* craft; char const* ufo; } skip_info; /* if we have known problems with some combinations, we can skip them */ skip_info const skip_list[] = { /* examples: */ // { 20, "forest", "large", "craft_drop_raptor", 0 }, // { 12, "forest", "large" "craft_drop_herakles", "craft_ufo_harvester" }, { -1, "frozen", "nature_medium",0, 0 }, { 11, "village", "medium", 0, 0 }, { 19, "village", "medium", 0, 0 }, { -1, "village", "medium_noufo", 0, 0 }, { -1, "village", "small", 0, 0 }, }; bool skip = false; for (skip_info const* e = skip_list; e != endof(skip_list); ++e) { if (e->seed >= 0 && i != e->seed) continue; if (e->map && !Q_streq(p, e->map)) continue; if (e->params && !Q_streq(md->params, e->params)) continue; if (e->craft && !Q_streq(craft, e->craft)) continue; if (e->ufo && !Q_streq(ufo, e->ufo)) continue; skip = true; break; } if (skip) continue; #endif /* for ufocrash map, the ufoname is the assemblyame */ if (Q_streq(p, "ufocrash")) asmName = Com_GetRandomMapAssemblyNameForCraft(ufo) + 1; /* +1 = get rid of the '+' */ else asmName = (const char*)LIST_GetByIdx(md->params, 0); char* entityString = SV_GetConfigString(CS_ENTITYSTRING); const int numPlaced = SV_AssembleMap(p, asmName, mapStr, posStr, entityString, i, false); ASSERT_TRUE(numPlaced != 0); time = (Sys_Milliseconds() - time); ASSERT_TRUE(time < 30000); if (time > 10000) Com_Printf("\nMap: %s Assembly: %s Seed: %i tiles: %i ms: %li\n", p, asmName, i, numPlaced, time); } didItOnce = true; if (!iterUfo) break; } if (!iterDrop) break; } } } }
/** * @todo need to merge UI model case, and the common case (look to be a copy-pasted code) */ void UI_DrawModelNode (uiNode_t *node, const char *source) { modelInfo_t mi; uiModel_t *model; vec3_t nodeorigin; vec3_t autoScale; vec3_t autoCenter; assert(UI_NodeInstanceOf(node, "model")); /**< We use model extradata */ if (source[0] == '\0') return; model = UI_GetUIModel(source); /* direct model name - no UI model definition */ if (!model) { /* prevent the searching for a model def in the next frame */ mi.model = R_FindModel(source); mi.name = source; if (!mi.model) { Com_Printf("Could not find model '%s'\n", source); return; } } /* compute the absolute origin ('origin' property is relative to the node center) */ UI_GetNodeAbsPos(node, nodeorigin); R_CleanupDepthBuffer(nodeorigin[0], nodeorigin[1], node->size[0], node->size[1]); if (EXTRADATA(node).clipOverflow) R_PushClipRect(nodeorigin[0], nodeorigin[1], node->size[0], node->size[1]); nodeorigin[0] += node->size[0] / 2 + EXTRADATA(node).origin[0]; nodeorigin[1] += node->size[1] / 2 + EXTRADATA(node).origin[1]; nodeorigin[2] = EXTRADATA(node).origin[2]; VectorMA(EXTRADATA(node).angles, cls.frametime, EXTRADATA(node).omega, EXTRADATA(node).angles); mi.origin = nodeorigin; mi.angles = EXTRADATA(node).angles; mi.scale = EXTRADATA(node).scale; mi.center = nullVector; mi.color = node->color; mi.mesh = 0; /* special case to draw models with UI model */ if (model) { UI_DrawModelNodeWithUIModel(node, source, &mi, model); if (EXTRADATA(node).clipOverflow) R_PopClipRect(); return; } /* if the node is linked to a parent, the parent will display it */ if (EXTRADATA(node).tag) { if (EXTRADATA(node).clipOverflow) R_PopClipRect(); return; } /* autoscale? */ if (EXTRADATA(node).autoscale) { const vec2_t size = {node->size[0] - node->padding, node->size[1] - node->padding}; R_ModelAutoScale(size, &mi, autoScale, autoCenter); } /* no animation */ mi.frame = 0; mi.oldframe = 0; mi.backlerp = 0; /* get skin */ if (EXTRADATA(node).skin && *EXTRADATA(node).skin) mi.skin = atoi(UI_GetReferenceString(node, EXTRADATA(node).skin)); else mi.skin = 0; /* do animations */ if (EXTRADATA(node).animation && *EXTRADATA(node).animation) { animState_t *as; const char *ref; ref = UI_GetReferenceString(node, EXTRADATA(node).animation); /* check whether the cvar value changed */ if (strncmp(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE)) { Q_strncpyz(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE); /* model has changed but mem is already reserved in pool */ if (EXTRADATA(node).animationState) { Mem_Free(EXTRADATA(node).animationState); EXTRADATA(node).animationState = NULL; } } if (!EXTRADATA(node).animationState) { as = (animState_t *) Mem_PoolAlloc(sizeof(*as), cl_genericPool, 0); if (!as) Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", mi.name, ref); R_AnimChange(as, mi.model, ref); EXTRADATA(node).animationState = as; } else { const char *anim; /* change anim if needed */ as = EXTRADATA(node).animationState; if (!as) Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", mi.name, ref); anim = R_AnimGetName(as, mi.model); if (anim && !Q_streq(anim, ref)) R_AnimChange(as, mi.model, ref); R_AnimRun(as, mi.model, cls.frametime * 1000); } mi.frame = as->frame; mi.oldframe = as->oldframe; mi.backlerp = as->backlerp; } /* draw the main model on the node */ R_DrawModelDirect(&mi, NULL, NULL); /* draw all children */ if (node->firstChild) { uiNode_t *child; modelInfo_t pmi = mi; for (child = node->firstChild; child; child = child->next) { const char *tag; char childSource[MAX_VAR]; const char* childRef; /* skip non "model" nodes */ if (child->behaviour != node->behaviour) continue; /* skip invisible child */ if (child->invis || !UI_CheckVisibility(child)) continue; OBJZERO(mi); mi.angles = EXTRADATA(child).angles; mi.scale = EXTRADATA(child).scale; mi.center = nullVector; mi.origin = EXTRADATA(child).origin; mi.color = pmi.color; /* get the anchor name to link the model into the parent */ tag = EXTRADATA(child).tag; /* init model name */ childRef = UI_GetReferenceString(child, EXTRADATA(child).model); if (Q_strnull(childRef)) childSource[0] = '\0'; else Q_strncpyz(childSource, childRef, sizeof(childSource)); mi.model = R_FindModel(childSource); mi.name = childSource; /* init skin */ if (EXTRADATA(child).skin && *EXTRADATA(child).skin) mi.skin = atoi(UI_GetReferenceString(child, EXTRADATA(child).skin)); else mi.skin = 0; R_DrawModelDirect(&mi, &pmi, tag); } } if (EXTRADATA(node).clipOverflow) R_PopClipRect(); }
/** * @brief Parse medals and ranks defined in the medals.ufo file. * @sa CL_ParseScriptFirst */ void CL_ParseRanks (const char* name, const char** text) { rank_t* rank; const char* errhead = "CL_ParseRanks: unexpected end of file (medal/rank "; const char* token; /* get name list body body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("CL_ParseRanks: rank/medal \"%s\" without body ignored\n", name); return; } for (int i = 0; i < ccs.numRanks; i++) { if (Q_streq(name, ccs.ranks[i].name)) { Com_Printf("CL_ParseRanks: Rank with same name '%s' already loaded.\n", name); return; } } /* parse ranks */ if (ccs.numRanks >= MAX_RANKS) { Com_Printf("CL_ParseRanks: Too many rank descriptions, '%s' ignored.\n", name); ccs.numRanks = MAX_RANKS; return; } rank = &ccs.ranks[ccs.numRanks++]; OBJZERO(*rank); rank->id = cgi->PoolStrDup(name, cp_campaignPool, 0); rank->level = -1; do { /* get the name type */ token = cgi->Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; if (cgi->Com_ParseBlockToken(name, text, rank, rankValues, cp_campaignPool, token)) { continue; } else if (Q_streq(token, "type")) { /* employeeType_t */ token = cgi->Com_EParse(text, errhead, name); if (!*text) return; /* error check is performed in E_GetEmployeeType function */ rank->type = E_GetEmployeeType(token); } else Com_Printf("CL_ParseRanks: unknown token \"%s\" ignored (medal/rank %s)\n", token, name); } while (*text); if (rank->image == nullptr || !strlen(rank->image)) cgi->Com_Error(ERR_DROP, "CL_ParseRanks: image is missing for rank %s", rank->id); if (rank->name == nullptr || !strlen(rank->name)) cgi->Com_Error(ERR_DROP, "CL_ParseRanks: name is missing for rank %s", rank->id); if (rank->shortname == nullptr || !strlen(rank->shortname)) rank->shortname = rank->name; if (rank->level == -1) cgi->Com_Error(ERR_DROP, "CL_ParseRanks: level is missing for rank %s", rank->id); }
/** * @brief Create lights out of patches and entity lights * @sa LightWorld * @sa BuildPatch */ void BuildLights (void) { int i; light_t* l; /* surfaces */ for (i = 0; i < MAX_MAP_FACES; i++) { /* iterate subdivided patches */ for(const patch_t* p = face_patches[i]; p; p = p->next) { if (VectorEmpty(p->light)) continue; numlights[config.compile_for_day]++; l = Mem_AllocType(light_t); VectorCopy(p->origin, l->origin); l->next = lights[config.compile_for_day]; lights[config.compile_for_day] = l; l->type = emit_surface; l->intensity = ColorNormalize(p->light, l->color); l->intensity *= p->area * config.surface_scale; } } /* entities (skip the world) */ for (i = 1; i < num_entities; i++) { float intensity; const char* color; const char* target; const entity_t* e = &entities[i]; const char* name = ValueForKey(e, "classname"); if (!Q_strstart(name, "light")) continue; /* remove those lights that are only for the night version */ if (config.compile_for_day) { const int spawnflags = atoi(ValueForKey(e, "spawnflags")); if (!(spawnflags & 1)) /* day */ continue; } numlights[config.compile_for_day]++; l = Mem_AllocType(light_t); GetVectorForKey(e, "origin", l->origin); /* link in */ l->next = lights[config.compile_for_day]; lights[config.compile_for_day] = l; intensity = FloatForKey(e, "light"); if (!intensity) intensity = 300.0; color = ValueForKey(e, "_color"); if (color && color[0] != '\0'){ if (sscanf(color, "%f %f %f", &l->color[0], &l->color[1], &l->color[2]) != 3) Sys_Error("Invalid _color entity property given: %s", color); ColorNormalize(l->color, l->color); } else VectorSet(l->color, 1.0, 1.0, 1.0); l->intensity = intensity * config.entity_scale; l->type = emit_point; target = ValueForKey(e, "target"); if (target[0] != '\0' || Q_streq(name, "light_spot")) { l->type = emit_spotlight; l->stopdot = FloatForKey(e, "_cone"); if (!l->stopdot) l->stopdot = 10; l->stopdot = cos(l->stopdot * torad); if (target[0] != '\0') { /* point towards target */ entity_t* e2 = FindTargetEntity(target); if (!e2) Com_Printf("WARNING: light at (%i %i %i) has missing target '%s' - e.g. create an info_null that has a 'targetname' set to '%s'\n", (int)l->origin[0], (int)l->origin[1], (int)l->origin[2], target, target); else { vec3_t dest; GetVectorForKey(e2, "origin", dest); VectorSubtract(dest, l->origin, l->normal); VectorNormalize(l->normal); } } else { /* point down angle */ const float angle = FloatForKey(e, "angle"); if (angle == ANGLE_UP) { l->normal[0] = l->normal[1] = 0.0; l->normal[2] = 1.0; } else if (angle == ANGLE_DOWN) { l->normal[0] = l->normal[1] = 0.0; l->normal[2] = -1.0; } else { l->normal[2] = 0; l->normal[0] = cos(angle * torad); l->normal[1] = sin(angle * torad); } } } } /* handle worldspawn light settings */ { const entity_t* e = &entities[0]; const char* ambient, *light, *angles, *color; float f; int i; if (config.compile_for_day) { ambient = ValueForKey(e, "ambient_day"); light = ValueForKey(e, "light_day"); angles = ValueForKey(e, "angles_day"); color = ValueForKey(e, "color_day"); } else { ambient = ValueForKey(e, "ambient_night"); light = ValueForKey(e, "light_night"); angles = ValueForKey(e, "angles_night"); color = ValueForKey(e, "color_night"); } if (light[0] != '\0') sun_intensity = atoi(light); if (angles[0] != '\0') { VectorClear(sun_angles); if (sscanf(angles, "%f %f", &sun_angles[0], &sun_angles[1]) != 2) Sys_Error("wrong angles values given: '%s'", angles); AngleVectors(sun_angles, sun_normal, nullptr, nullptr); } if (color[0] != '\0') { GetVectorFromString(color, sun_color); ColorNormalize(sun_color, sun_color); } if (ambient[0] != '\0') GetVectorFromString(ambient, sun_ambient_color); /* optionally pull brightness from worldspawn */ f = FloatForKey(e, "brightness"); if (f > 0.0) config.brightness = f; /* saturation as well */ f = FloatForKey(e, "saturation"); if (f > 0.0) config.saturation = f; else Verb_Printf(VERB_EXTRA, "Invalid saturation setting (%f) in worldspawn found\n", f); f = FloatForKey(e, "contrast"); if (f > 0.0) config.contrast = f; else Verb_Printf(VERB_EXTRA, "Invalid contrast setting (%f) in worldspawn found\n", f); /* lightmap resolution downscale (e.g. 4 = 1 << 4) */ i = atoi(ValueForKey(e, "quant")); if (i >= 1 && i <= 6) config.lightquant = i; else Verb_Printf(VERB_EXTRA, "Invalid quant setting (%i) in worldspawn found\n", i); } Verb_Printf(VERB_EXTRA, "light settings:\n * intensity: %i\n * sun_angles: pitch %f yaw %f\n * sun_color: %f:%f:%f\n * sun_ambient_color: %f:%f:%f\n", sun_intensity, sun_angles[0], sun_angles[1], sun_color[0], sun_color[1], sun_color[2], sun_ambient_color[0], sun_ambient_color[1], sun_ambient_color[2]); Verb_Printf(VERB_NORMAL, "%i direct lights for %s lightmap\n", numlights[config.compile_for_day], (config.compile_for_day ? "day" : "night")); }
/** * @brief Initialize a node behaviour memory, after registration, and before unsing it. * @param behaviour Behaviour to initialize */ void UI_InitializeNodeBehaviour (uiBehaviour_t* behaviour) { if (behaviour->isInitialized) return; /* everything inherits 'abstractnode' */ if (behaviour->extends == NULL && !Q_streq(behaviour->name, "abstractnode")) { behaviour->extends = "abstractnode"; } if (behaviour->extends) { int i = 0; /** TODO Find a way to remove that, if possible */ behaviour->super = UI_GetNodeBehaviour(behaviour->extends); UI_InitializeNodeBehaviour(behaviour->super); while (qtrue) { const size_t pos = virtualFunctions[i]; uintptr_t superFunc; uintptr_t func; if (pos == -1) break; /* cache super function if we don't overwrite it */ superFunc = *(uintptr_t*)((byte*)behaviour->super + pos); func = *(uintptr_t*)((byte*)behaviour + pos); if (func == 0 && superFunc != 0) *(uintptr_t*)((byte*)behaviour + pos) = superFunc; i++; } } /* sort properties by alphabet */ if (behaviour->localProperties) { int i = 0; const value_t* previous; const value_t** oldmemory = behaviour->localProperties; behaviour->localProperties = UI_AllocHunkMemory(sizeof(value_t*) * (behaviour->propertyCount+1), STRUCT_MEMORY_ALIGN, qfalse); if (behaviour->localProperties == NULL) { Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: UI memory hunk exceeded - increase the size"); } previous = NULL; for (i = 0; i < behaviour->propertyCount; i++) { const value_t* better = NULL; const value_t** current; /* search the next element after previous */ for (current = oldmemory; *current != NULL; current++) { if (previous != NULL && Q_strcasecmp(previous->string, (*current)->string) >= 0) { continue; } if (better == NULL || Q_strcasecmp(better->string, (*current)->string) >= 0) { better = *current; } } previous = better; behaviour->localProperties[i] = better; } behaviour->localProperties[behaviour->propertyCount] = NULL; Mem_Free(oldmemory); } /* property must not overwrite another property */ if (behaviour->super && behaviour->localProperties) { const value_t** property = behaviour->localProperties; while (*property) { const value_t *p = UI_GetPropertyFromBehaviour(behaviour->super, (*property)->string); #if 0 /**< @todo not possible at the moment, not sure its the right way */ const uiBehaviour_t *b = UI_GetNodeBehaviour(current->string); #endif if (p != NULL) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' overwrite another property", (*property)->string, behaviour->name); #if 0 /**< @todo not possible at the moment, not sure its the right way */ if (b != NULL) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' use the name of an existing node behaviour", (*property)->string, behaviour->name); #endif property++; } } /* Sanity: A property must not be outside the node memory */ if (behaviour->localProperties) { const int size = sizeof(uiNode_t) + behaviour->extraDataSize; const value_t** property = behaviour->localProperties; while (*property) { if ((*property)->type != V_UI_NODEMETHOD && (*property)->ofs + (*property)->size > size) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' is outside the node memory. The C code need a fix.", (*property)->string, behaviour->name); property++; } } behaviour->isInitialized = qtrue; }
/** * @brief Copies an entry from the building description file into the list of building types. * @note Parses one "building" entry in the basemanagement.ufo file and writes * it into the next free entry in bmBuildings[0], which is the list of buildings * in the first base (building_t). * @param[in] name Unique script id of a building. This is parsed from "building xxx" -> id=xxx. * @param[in] text the whole following text that is part of the "building" item definition in .ufo. * @param[in] link Bool value that decides whether to link the tech pointer in or not * @sa CL_ParseScriptFirst (link is false here) * @sa CL_ParseScriptSecond (link it true here) */ void B_ParseBuildings (const char* name, const char** text, bool link) { building_t* building; technology_t* techLink; const char* errhead = "B_ParseBuildings: unexpected end of file (names "; const char* token; /* get id list body */ token = Com_Parse(text); if (!*text || *token != '{') { cgi->Com_Printf("B_ParseBuildings: building \"%s\" without body ignored\n", name); return; } if (ccs.numBuildingTemplates >= MAX_BUILDINGS) cgi->Com_Error(ERR_DROP, "B_ParseBuildings: too many buildings"); if (!link) { for (int i = 0; i < ccs.numBuildingTemplates; i++) { if (Q_streq(ccs.buildingTemplates[i].id, name)) { cgi->Com_Printf("B_ParseBuildings: Second building with same name found (%s) - second ignored\n", name); return; } } /* new entry */ building = &ccs.buildingTemplates[ccs.numBuildingTemplates]; OBJZERO(*building); building->id = cgi->PoolStrDup(name, cp_campaignPool, 0); cgi->Com_DPrintf(DEBUG_CLIENT, "...found building %s\n", building->id); /* set standard values */ building->tpl = building; /* Self-link just in case ... this way we can check if it is a template or not. */ building->idx = -1; /* No entry in buildings list (yet). */ building->base = nullptr; building->buildingType = MAX_BUILDING_TYPE; building->dependsBuilding = nullptr; building->maxCount = -1; /* Default: no limit */ building->size[0] = 1; building->size[1] = 1; ccs.numBuildingTemplates++; do { /* get the name type */ token = cgi->Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* get values */ if (Q_streq(token, "type")) { token = cgi->Com_EParse(text, errhead, name); if (!*text) return; building->buildingType = B_GetBuildingTypeByBuildingID(token); if (building->buildingType >= MAX_BUILDING_TYPE) cgi->Com_Printf("didn't find buildingType '%s'\n", token); } else { /* no linking yet */ if (Q_streq(token, "depends")) { cgi->Com_EParse(text, errhead, name); if (!*text) return; } else { if (!cgi->Com_ParseBlockToken(name, text, building, valid_building_vars, cp_campaignPool, token)) cgi->Com_Printf("B_ParseBuildings: unknown token \"%s\" ignored (building %s)\n", token, name); } } } while (*text); if (building->size[0] < 1 || building->size[1] < 1 || building->size[0] >= BASE_SIZE || building->size[1] >= BASE_SIZE) { cgi->Com_Printf("B_ParseBuildings: Invalid size for building %s (%i, %i)\n", building->id, (int)building->size[0], (int)building->size[1]); ccs.numBuildingTemplates--; } } else { building = B_GetBuildingTemplate(name); if (!building) cgi->Com_Error(ERR_DROP, "B_ParseBuildings: Could not find building with id %s\n", name); techLink = RS_GetTechByProvided(name); if (techLink) building->tech = techLink; do { /* get the name type */ token = cgi->Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* get values */ if (Q_streq(token, "depends")) { const building_t* dependsBuilding = B_GetBuildingTemplate(cgi->Com_EParse(text, errhead, name)); if (!dependsBuilding) cgi->Com_Error(ERR_DROP, "Could not find building depend of %s\n", building->id); building->dependsBuilding = dependsBuilding; if (!*text) return; } } while (*text); } }
/* ====================== SV_Map the full syntax is: map [*]<map>$<startspot>+<nextserver> command from the console or progs. Map can also be a.cin, .pcx, or .dm2 file Nextserver is used to allow a cinematic to play, then proceed to another level: map tram.cin+jail_e3 ====================== */ void SV_Map (qboolean attractloop, const char *levelstring, qboolean loadgame) { char level[MAX_QPATH]; char *ch; int l; char spawnpoint[MAX_QPATH]; strcpy(level, levelstring); // jit - copy level string before it gets modified by other commands (since it's a command argument) sv.loadgame = loadgame; sv.attractloop = attractloop; if (sv.state == ss_dead && !sv.loadgame) SV_InitGame(); // the game is just starting // if there is a + in the map, set nextserver to the remainder ch = strstr(level, "+"); if (ch) { *ch = 0; Cvar_Set("nextserver", va("gamemap \"%s\"", ch + 1)); } else { Cvar_Set("nextserver", ""); } //ZOID special hack for end game screen in coop mode if (Cvar_VariableValue("coop") && Q_strcaseeq(level, "victory.pcx")) Cvar_Set("nextserver", "gamemap \"*base1\""); // if there is a $, use the remainder as a spawnpoint ch = strstr(level, "$"); if (ch) { *ch = 0; strcpy(spawnpoint, ch + 1); } else { spawnpoint[0] = 0; } // skip the end-of-unit flag if necessary if (level[0] == '*') strcpy (level, level+1); l = strlen(level); if (l > 4 && Q_streq(level + l - 4, ".cin")) { SCR_BeginLoadingPlaque(NULL); // for local system SV_BroadcastCommand("changing\n"); SV_SpawnServer(level, spawnpoint, ss_cinematic, attractloop, loadgame); } else if (l > 4 && Q_streq(level + l - 4, ".dm2")) { SCR_BeginLoadingPlaque(NULL); // for local system SV_BroadcastCommand("changing\n"); SV_SpawnServer(level, spawnpoint, ss_demo, attractloop, loadgame); } else if (l > 4 && Q_streq(level + l - 4, ".pcx")) { SCR_BeginLoadingPlaque(NULL); // for local system SV_BroadcastCommand("changing\n"); SV_SpawnServer(level, spawnpoint, ss_pic, attractloop, loadgame); } else { char changing_cmd[1024]; if (!dedicated->value) SCR_BeginLoadingPlaque(level); // for local system Com_sprintf(changing_cmd, sizeof(changing_cmd), "changing \"%s\"\n", level); SV_BroadcastCommand(changing_cmd); SV_SendClientMessages(); SV_SpawnServer(level, spawnpoint, ss_game, attractloop, loadgame); Cbuf_CopyToDefer(); } SV_BroadcastCommand("reconnect\n"); }
/** * @brief Sets a cvar values * Handles write protection and latched cvars as expected * @param[in] varName Which cvar * @param[in] value Set the cvar to the value specified by 'value' * @param[in] force Force the update of the cvar */ static cvar_t *Cvar_Set2 (const char *varName, const char *value, bool force) { cvar_t *var; if (!value) return NULL; var = Cvar_FindVar(varName); /* create it */ if (!var) return Cvar_Get(varName, value); if (var->flags & (CVAR_USERINFO | CVAR_SERVERINFO)) { if (!Cvar_InfoValidate(value)) { Com_Printf("invalid info cvar value '%s' of cvar '%s'\n", value, varName); return var; } } if (!force) { if (var->flags & CVAR_NOSET) { Com_Printf("%s is write protected.\n", varName); return var; } #ifndef DEBUG if (var->flags & CVAR_DEVELOPER) { Com_Printf("%s is a developer cvar.\n", varName); return var; } #endif if (var->flags & CVAR_LATCH) { if (var->latchedString) { if (Q_streq(value, var->latchedString)) return var; Mem_Free(var->latchedString); var->latchedString = NULL; } else { if (Q_streq(value, var->string)) return var; } /* if we are running a server */ if (Com_ServerState()) { Com_Printf("%s will be changed for next game.\n", varName); var->latchedString = Mem_PoolStrDup(value, com_cvarSysPool, 0); } else { Mem_Free(var->oldString); var->oldString = var->string; var->string = Mem_PoolStrDup(value, com_cvarSysPool, 0); var->value = atof(var->string); var->integer = atoi(var->string); } if (var->check && var->check(var)) Com_Printf("Invalid value for cvar %s\n", varName); return var; } } else { Mem_Free(var->latchedString); var->latchedString = NULL; } if (Q_streq(value, var->string)) return var; /* not changed */ if (var->flags & CVAR_R_MASK) Com_SetRenderModified(true); Mem_Free(var->oldString); /* free the old value string */ var->oldString = var->string; var->modified = true; if (var->flags & CVAR_USERINFO) Com_SetUserinfoModified(true); /* transmit at next opportunity */ var->string = Mem_PoolStrDup(value, com_cvarSysPool, 0); var->value = atof(var->string); var->integer = atoi(var->string); if (var->check && var->check(var)) { Com_Printf("Invalid value for cvar %s\n", varName); return var; } Cvar_ExecuteChangeListener(var); return var; }
static inline bool IsInvalidEntityToken (const char* token) { return Q_streq(token, "}") || Q_streq(token, "{"); }
/** * @brief Called at client startup * @note not called for dedicated servers * parses all *.ufos that are needed for single- and multiplayer * @sa Com_ParseScripts * @sa CL_ParseScriptSecond * @sa CL_ParseScriptFirst * @note Nothing here should depends on items, equipments, actors and all other * entities that are parsed in Com_ParseScripts (because maybe items are not parsed * but e.g. techs would need those parsed items - thus we have to parse e.g. techs * at a later stage) * @note This data is persistent until you shutdown the game * @return True if the parsing function succeeded. */ bool CL_ParseClientData (const char* type, const char* name, const char** text) { #ifndef COMPILE_UNITTESTS static int progressCurrent = 0; progressCurrent++; if (progressCurrent % 10 == 0) SCR_DrawLoadingScreen(false, std::min(progressCurrent * 30 / 1500, 30)); #endif if (Q_streq(type, "window")) return UI_ParseWindow(type, name, text); else if (Q_streq(type, "component")) return UI_ParseComponent(type, name, text); else if (Q_streq(type, "particle")) CL_ParseParticle(name, text); else if (Q_streq(type, "language")) CL_ParseLanguages(name, text); else if (Q_streq(type, "font")) return UI_ParseFont(name, text); else if (Q_streq(type, "tutorial")) TUT_ParseTutorials(name, text); else if (Q_streq(type, "menu_model")) return UI_ParseUIModel(name, text); else if (Q_streq(type, "sprite")) return UI_ParseSprite(name, text); else if (Q_streq(type, "sequence")) CL_ParseSequence(name, text); else if (Q_streq(type, "music")) M_ParseMusic(name, text); else if (Q_streq(type, "actorskin")) CL_ParseActorSkin(name, text); else if (Q_streq(type, "cgame")) GAME_ParseModes(name, text); else if (Q_streq(type, "tip")) CL_ParseTipOfTheDay(name, text); return true; }
/** * @brief Responses to broadcasts, etc * @sa CL_ReadPackets * @sa CL_Frame * @sa SVC_DirectConnect * @param[in,out] msg The client stream message buffer to read from */ static void CL_ConnectionlessPacket (dbuffer* msg) { char s[512]; NET_ReadStringLine(msg, s, sizeof(s)); Cmd_TokenizeString(s, false); const char* c = Cmd_Argv(0); Com_DPrintf(DEBUG_CLIENT, "server OOB: %s (%s)\n", c, Cmd_Args()); /* server connection */ if (Q_streq(c, CL_CMD_CLIENT_CONNECT)) { int i; for (i = 1; i < Cmd_Argc(); i++) { if (char const* const p = Q_strstart(Cmd_Argv(i), "dlserver=")) { Com_sprintf(cls.downloadReferer, sizeof(cls.downloadReferer), "ufo://%s", cls.servername); CL_SetHTTPServer(p); if (cls.downloadServer[0]) Com_Printf("HTTP downloading enabled, URL: %s\n", cls.downloadServer); } } if (cls.state == ca_connected) { Com_Printf("Dup connect received. Ignored.\n"); return; } dbuffer buf(5); NET_WriteByte(&buf, clc_stringcmd); NET_WriteString(&buf, NET_STATE_NEW "\n"); NET_WriteMsg(cls.netStream, buf); GAME_InitMissionBriefing(_("Loading")); return; } /* remote command from gui front end */ if (Q_streq(c, CL_CMD_COMMAND)) { if (!NET_StreamIsLoopback(cls.netStream)) { Com_Printf("Command packet from remote host. Ignored.\n"); return; } else { char str[512]; NET_ReadString(msg, str, sizeof(str)); Cbuf_AddText("%s\n", str); } return; } /* ping from server */ if (Q_streq(c, CL_CMD_PING)) { NET_OOB_Printf(cls.netStream, SV_CMD_ACK); return; } /* echo request from server */ if (Q_streq(c, CL_CMD_ECHO)) { NET_OOB_Printf(cls.netStream, "%s", Cmd_Argv(1)); return; } /* print */ if (Q_streq(c, SV_CMD_PRINT)) { NET_ReadString(msg, popupText, sizeof(popupText)); /* special reject messages needs proper handling */ if (strstr(popupText, REJ_PASSWORD_REQUIRED_OR_INCORRECT)) { UI_PushWindow("serverpassword"); if (Q_strvalid(Cvar_GetString("password"))) { Cvar_Set("password", ""); CL_Drop(); UI_Popup(_("Connection failure"), _("The password you specified was wrong.")); } else { CL_Drop(); UI_Popup(_("Connection failure"), _("This server requires a password.")); } } else if (strstr(popupText, REJ_SERVER_FULL)) { CL_Drop(); UI_Popup(_("Connection failure"), _("This server is full.")); } else if (strstr(popupText, REJ_BANNED)) { CL_Drop(); UI_Popup(_("Connection failure"), _("You are banned on this server.")); } else if (strstr(popupText, REJ_GAME_ALREADY_STARTED)) { CL_Drop(); UI_Popup(_("Connection failure"), _("The game has already started.")); } else if (strstr(popupText, REJ_SERVER_VERSION_MISMATCH)) { CL_Drop(); UI_Popup(_("Connection failure"), _("The server is running a different version of the game.")); } else if (strstr(popupText, BAD_RCON_PASSWORD)) { Cvar_Set("rcon_password", ""); UI_Popup(_("Bad rcon password"), _("The rcon password you specified was wrong.")); } else if (strstr(popupText, REJ_CONNECTION_REFUSED)) { CL_Drop(); UI_Popup(_("Connection failure"), _("The server refused the connection.")); } else if (Q_strvalid(popupText)) { UI_Popup(_("Notice"), _(popupText)); } return; } if (!GAME_HandleServerCommand(c, msg)) Com_Printf("Unknown command received \"%s\"\n", c); }
void uiOptionTreeNode::draw (uiNode_t* node) { uiNode_t* option; const char* ref; const char* font; vec2_t pos; int fontHeight; int currentY; int currentDecY = 0; const float* textColor; int count = 0; uiOptionIterator_t iterator; if (!systemExpand) systemExpand = UI_GetSpriteByName("icons/system_expand"); if (!systemCollapse) systemCollapse = UI_GetSpriteByName("icons/system_collapse"); ref = UI_AbstractOptionGetCurrentValue(node); if (ref == nullptr) return; UI_GetNodeAbsPos(node, pos); if (EXTRADATA(node).background) { UI_DrawSpriteInBox(false, EXTRADATA(node).background, SPRITE_STATUS_NORMAL, pos[0], pos[1], node->box.size[0], node->box.size[1]); } font = UI_GetFontFromNode(node); fontHeight = EXTRADATA(node).lineHeight; currentY = pos[1] + node->padding; if (fontHeight == 0) fontHeight = UI_FontGetHeight(font); else { const int height = UI_FontGetHeight(font); currentDecY = (fontHeight - height) / 2; } /* skip option over current position */ option = UI_OptionTreeNodeGetFirstOption(node); UI_OptionTreeNodeUpdateScroll(node); option = UI_InitOptionIteratorAtIndex(EXTRADATA(node).scrollY.viewPos, option, &iterator); /* draw all available options for this selectbox */ for (; option; option = UI_OptionIteratorNextOption(&iterator)) { int decX; /* outside the node */ if (currentY + fontHeight > pos[1] + node->box.size[1] - node->padding) { count++; break; } /* draw the hover effect */ if (OPTIONEXTRADATA(option).hovered) UI_DrawFill(pos[0] + node->padding, currentY, node->box.size[0] - node->padding - node->padding, fontHeight, node->color); /* text color */ if (Q_streq(OPTIONEXTRADATA(option).value, ref)) { textColor = node->selectedColor; } else if (node->disabled || option->disabled) { textColor = node->disabledColor; } else if (option->color[3] == 0.0f) { textColor = node->color; } else { textColor = option->color; } /* print the option label */ decX = pos[0] + node->padding + iterator.depthPos * DEPTH_WIDTH; R_Color(nullptr); if (option->firstChild) { uiSprite_t* icon = OPTIONEXTRADATA(option).collapsed ? systemExpand : systemCollapse; UI_DrawSpriteInBox(OPTIONEXTRADATA(option).flipIcon, icon, SPRITE_STATUS_NORMAL, decX, currentY, icon->size[0], fontHeight); } decX += COLLAPSEBUTTON_WIDTH; if (OPTIONEXTRADATA(option).icon) { uiSpriteStatus_t iconStatus = SPRITE_STATUS_NORMAL; if (option->disabled) iconStatus = SPRITE_STATUS_DISABLED; UI_DrawSpriteInBox(OPTIONEXTRADATA(option).flipIcon, OPTIONEXTRADATA(option).icon, iconStatus, decX, currentY, OPTIONEXTRADATA(option).icon->size[0], fontHeight); decX += OPTIONEXTRADATA(option).icon->size[0] + fontHeight / 4; } const char* label = CL_Translate(OPTIONEXTRADATA(option).label); R_Color(textColor); UI_DrawString(font, ALIGN_UL, decX, currentY + currentDecY, pos[0], node->box.size[0] - node->padding - node->padding, 0, label, 0, 0, nullptr, false, LONGLINES_PRETTYCHOP); /* next entries' position */ currentY += fontHeight; count++; } R_Color(nullptr); }
bool SCP_Load (xmlNode_t *parent) { xmlNode_t *node; xmlNode_t *snode; node = cgi->XML_GetNode(parent, SAVE_STATICCAMPAIGN); if (!node) { return false; } SCP_Parse(); /* read static campaign data */ for (snode = cgi->XML_GetNode(node, SAVE_STATICCAMPAIGN_STAGE); snode; snode = cgi->XML_GetNextNode(snode, node, SAVE_STATICCAMPAIGN_STAGE)) { xmlNode_t *stateNode; const char *id = cgi->XML_GetString(snode, SAVE_STATICCAMPAIGN_STAGENAME); stageState_t *state = SCP_CampaignActivateStage(id); if (!state) { Com_Printf("......error: unable to load campaign, unknown stage '%s'\n", id); return false; } cgi->XML_GetDate(snode, SAVE_STATICCAMPAIGN_STAGEDATE, &state->start.day, &state->start.sec); int num = 0; for (stateNode = cgi->XML_GetNode(snode, SAVE_STATICCAMPAIGN_SETSTATE); stateNode; stateNode = cgi->XML_GetNextNode(stateNode, snode, SAVE_STATICCAMPAIGN_SETSTATE)) { num++; setState_t *set; int j; const char *name = cgi->XML_GetString(stateNode, SAVE_STATICCAMPAIGN_SETSTATENAME); for (j = 0, set = &scd->set[state->def->first]; j < state->def->num; j++, set++) if (Q_streq(name, set->def->name)) break; if (j >= state->def->num) { Com_Printf("......error: Set '%s' not found (%i/%i)\n", name, num, state->def->num); return false; } set->active = cgi->XML_GetBool(stateNode, SAVE_STATICCAMPAIGN_SETSTATEACTIVE, false); set->num = cgi->XML_GetInt(stateNode, SAVE_STATICCAMPAIGN_SETSTATENUM, 0); set->done = cgi->XML_GetInt(stateNode, SAVE_STATICCAMPAIGN_SETSTATEDONE, 0); cgi->XML_GetDate(stateNode, SAVE_STATICCAMPAIGN_SETSTATESTARTDATE, &set->start.day, &set->start.sec); cgi->XML_GetDate(stateNode, SAVE_STATICCAMPAIGN_SETSTATEEVENTDATE, &set->event.day, &set->event.sec); } if (num != state->def->num) Com_Printf("......warning: Different number of sets: savegame: %i, scripts: %i\n", num, state->def->num); } for (snode = cgi->XML_GetNode(node, SAVE_STATICCAMPAIGN_ACTIVEMISSION); snode; snode = cgi->XML_GetNextNode(snode, node, SAVE_STATICCAMPAIGN_ACTIVEMISSION)) { int j; const char *name = cgi->XML_GetString(snode, SAVE_STATICCAMPAIGN_STAGESETNAME); actMis_t *mis = &scd->activeMissions[scd->numActiveMissions++]; mis->def = NULL; mis->cause = NULL; for (j = 0; j < scd->numStageSets; j++) if (Q_streq(name, scd->stageSets[j].name)) { mis->cause = &scd->set[j]; break; } if (j >= scd->numStageSets) { Com_Printf("......error: Stage set '%s' not found\n", name); return false; } /* get mission definition */ name = cgi->XML_GetString(snode, SAVE_STATICCAMPAIGN_MISSIONNAME); for (j = 0; j < scd->numMissions; j++) if (Q_streq(name, scd->missions[j].id)) { mis->def = &scd->missions[j]; break; } /* ignore incomplete info */ if (!mis->cause || !mis->def) { Com_Printf("......error: Incomplete mission info for mission %s\n", name); return false; } mis->def->count = cgi->XML_GetInt(snode, SAVE_STATICCAMPAIGN_MISSIONCOUNT, 0); name = cgi->XML_GetString(snode, SAVE_STATICCAMPAIGN_MISSIONID); mis->mission = CP_GetMissionByIDSilent(name); if (!mis->mission) { Com_Printf("......error: Could not find mission for %s\n", name); return false; } /* read time */ cgi->XML_GetDate(snode, SAVE_STATICCAMPAIGN_MISSIONEXPIREDATE, &mis->expire.day, &mis->expire.sec); } return true; }
/* =========== Joy_AdvancedUpdate_f =========== */ void Joy_AdvancedUpdate_f (void) { // called once by IN_ReadJoystick and by user whenever an update is needed // cvars are now available int i; DWORD dwTemp; // initialize all the maps for (i = 0; i < JOY_MAX_AXES; i++) { dwAxisMap[i] = AxisNada; dwControlMap[i] = JOY_ABSOLUTE_AXIS; pdwRawValue[i] = RawValuePointer(i); } if ( joy_advanced->value == 0.0) { // default joystick initialization // 2 axes only with joystick control dwAxisMap[JOY_AXIS_X] = AxisTurn; // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS; dwAxisMap[JOY_AXIS_Y] = AxisForward; // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS; } else { if (!Q_streq(joy_name->string, "joystick")) { // notify user of advanced controller Com_Printf ("\n%s configured.\n\n", joy_name->string); } // advanced initialization here // data supplied by user via joy_axisn cvars dwTemp = (DWORD) joy_advaxisx->value; dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; dwTemp = (DWORD) joy_advaxisy->value; dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; dwTemp = (DWORD) joy_advaxisz->value; dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; dwTemp = (DWORD) joy_advaxisr->value; dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; dwTemp = (DWORD) joy_advaxisu->value; dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; dwTemp = (DWORD) joy_advaxisv->value; dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; } // compute the axes to collect from DirectInput joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV; for (i = 0; i < JOY_MAX_AXES; i++) { if (dwAxisMap[i] != AxisNada) { joy_flags |= dwAxisFlags[i]; } } }
static void UI_SelectBoxNodeDraw (uiNode_t *node) { uiNode_t* option; int selBoxX, selBoxY; const char *ref; const char *font; vec2_t nodepos; const char* imageName; const image_t *image; static vec4_t invisColor = {1.0, 1.0, 1.0, 0.7}; ref = UI_AbstractOptionGetCurrentValue(node); if (ref == NULL) return; UI_GetNodeAbsPos(node, nodepos); imageName = UI_GetReferenceString(node, node->image); if (!imageName) imageName = "ui/selectbox"; image = UI_LoadImage(imageName); font = UI_GetFontFromNode(node); selBoxX = nodepos[0] + SELECTBOX_SIDE_WIDTH; selBoxY = nodepos[1] + SELECTBOX_SPACER; /* left border */ UI_DrawNormImage(qfalse, nodepos[0], nodepos[1], SELECTBOX_SIDE_WIDTH, node->size[1], SELECTBOX_SIDE_WIDTH, SELECTBOX_DEFAULT_HEIGHT, 0.0f, 0.0f, image); /* stretched middle bar */ UI_DrawNormImage(qfalse, nodepos[0] + SELECTBOX_SIDE_WIDTH, nodepos[1], node->size[0]-SELECTBOX_SIDE_WIDTH-SELECTBOX_RIGHT_WIDTH, node->size[1], 12.0f, SELECTBOX_DEFAULT_HEIGHT, 7.0f, 0.0f, image); /* right border (arrow) */ UI_DrawNormImage(qfalse, nodepos[0] + node->size[0] - SELECTBOX_RIGHT_WIDTH, nodepos[1], SELECTBOX_DEFAULT_HEIGHT, node->size[1], 12.0f + SELECTBOX_RIGHT_WIDTH, SELECTBOX_DEFAULT_HEIGHT, 12.0f, 0.0f, image); /* draw the label for the current selected option */ for (option = UI_AbstractOptionGetFirstOption(node); option; option = option->next) { const char *label; if (!Q_streq(OPTIONEXTRADATA(option).value, ref)) continue; if (option->invis) R_Color(invisColor); label = OPTIONEXTRADATA(option).label; if (label[0] == '_') label = _(label + 1); UI_DrawString(font, ALIGN_UL, selBoxX, selBoxY, selBoxX, node->size[0] - 4, 0, label, 0, 0, NULL, qfalse, LONGLINES_PRETTYCHOP); R_Color(NULL); break; } /* must we draw the drop-down list */ if (UI_GetMouseCapture() == node) { UI_CaptureDrawOver(node); } }
/** * @note Think functions are only executed when the match is running * or in other word, the game has started */ void G_MissionThink (edict_t *self) { edict_t *chain = self->groupMaster; edict_t *ent; int team; if (!G_MatchIsRunning()) return; /* when every player has joined the match - spawn the mission target * particle (if given) to mark the trigger */ if (self->particle) { G_SpawnParticle(self->origin, self->spawnflags, self->particle); /* This is automatically freed on map shutdown */ self->particle = NULL; } if (!chain) chain = self; while (chain) { if (chain->type == ET_MISSION) { if (chain->item) { const invList_t *ic; G_GetFloorItems(chain); ic = FLOOR(chain); if (!ic) { /* reset the counter if there is no item */ chain->count = 0; return; } for (; ic; ic = ic->next) { const objDef_t *od = ic->item.t; assert(od); /* not the item we are looking for */ if (Q_streq(od->id, chain->item)) break; } if (!ic) { /* reset the counter if it's not the searched item */ chain->count = 0; return; } } if (chain->time) { /* not every edict in the group chain has * been occupied long enough */ if (!chain->count || level.actualRound - chain->count < chain->time) return; } /* not destroyed yet */ if ((chain->flags & FL_DESTROYABLE) && chain->HP) return; } chain = chain->groupChain; } if (self->use) self->use(self, NULL); /* store team before the edict is released */ team = self->team; chain = self->groupMaster; if (!chain) chain = self; while (chain) { if (chain->item != NULL) { edict_t *item = G_GetEdictFromPos(chain->pos, ET_ITEM); if (item != NULL) { if (!G_InventoryRemoveItemByID(chain->item, item, gi.csi->idFloor)) { Com_Printf("Could not remove item '%s' from floor edict %i\n", chain->item, item->number); } else { G_AppearPerishEvent(G_VisToPM(item->visflags), false, item, NULL); } } } if (chain->particle != NULL) { /** @todo not yet working - particle stays active */ edict_t *particle = G_GetEdictFromPos(chain->pos, ET_PARTICLE); if (particle != NULL) { G_AppearPerishEvent(PM_ALL, false, particle, NULL); G_FreeEdict(particle); } } ent = chain->groupChain; /* free the trigger */ if (chain->child) G_FreeEdict(chain->child); /* free the group chain */ G_FreeEdict(chain); chain = ent; } self = NULL; /* still active mission edicts left */ ent = NULL; while ((ent = G_EdictsGetNextInUse(ent))) if (ent->type == ET_MISSION && ent->team == team) return; G_MatchEndTrigger(team, 10); }
/** * @brief Returns what the actor can see. */ static int AIL_see (lua_State *L) { int vision, team; int i, j, k, n, cur; Edict *check = nullptr; aiActor_t target; Edict *sorted[MAX_EDICTS], *unsorted[MAX_EDICTS]; float distLookup[MAX_EDICTS]; /* Defaults. */ team = TEAM_ALL; vision = 0; /* Handle parameters. */ if ((lua_gettop(L) > 0)) { /* Get what to "see" with. */ if (lua_isstring(L, 1)) { const char *s = lua_tostring(L, 1); /** @todo Properly implement at edict level, get rid of magic numbers. * These are only "placeholders". */ if (Q_streq(s, "all")) vision = 0; else if (Q_streq(s, "sight")) vision = 1; else if (Q_streq(s, "psionic")) vision = 2; else if (Q_streq(s, "infrared")) vision = 3; else AIL_invalidparameter(1); } else AIL_invalidparameter(1); /* We now check for different teams. */ if ((lua_gettop(L) > 1)) { if (lua_isstring(L, 2)) { const char *s = lua_tostring(L, 2); team = AIL_toTeamInt(s); } else AIL_invalidparameter(2); } } n = 0; /* Get visible things. */ while ((check = G_EdictsGetNextLivingActor(check))) { if (AIL_ent == check) continue; if (vision == 0 && (team == TEAM_ALL || check->team == team) /* Check for team match if needed. */ && G_Vis(AIL_ent->team, AIL_ent, check, VT_NOFRUSTUM)) { distLookup[n] = VectorDistSqr(AIL_ent->pos, check->pos); unsorted[n++] = check; } } /* Sort by distance - nearest first. */ for (i = 0; i < n; i++) { /* Until we fill sorted */ cur = -1; for (j = 0; j < n; j++) { /* Check for closest */ /* Is shorter then current minimum? */ if (cur < 0 || distLookup[j] < distLookup[cur]) { /* Check if not already in sorted. */ for (k = 0; k < i; k++) if (sorted[k] == unsorted[j]) break; /* Not already sorted and is new minimum. */ if (k == i) cur = j; } } sorted[i] = unsorted[cur]; } /* Now save it in a Lua table. */ lua_newtable(L); for (i = 0; i < n; i++) { lua_pushnumber(L, i + 1); /* index, starts with 1 */ target.ent = sorted[i]; lua_pushactor(L, &target); /* value */ lua_rawset(L, -3); /* store the value in the table */ } return 1; /* Returns the table of actors. */ }
/** * @brief Checks if the given object/item matched the given filter type. * @param[in] obj A pointer to an objDef_t item. * @param[in] filterType Filter type to check against. * @return @c true if obj is in filterType */ bool INV_ItemMatchesFilter (const objDef_t *obj, const itemFilterTypes_t filterType) { int i; if (!obj) return false; switch (filterType) { case FILTER_S_PRIMARY: if (obj->isPrimary && !obj->isHeavy) return true; /* Check if one of the items that uses this ammo matches this filter type. */ for (i = 0; i < obj->numWeapons; i++) { const objDef_t *weapon = obj->weapons[i]; if (weapon && weapon != obj && INV_ItemMatchesFilter(weapon, filterType)) return true; } break; case FILTER_S_SECONDARY: if (obj->isSecondary && !obj->isHeavy) return true; /* Check if one of the items that uses this ammo matches this filter type. */ for (i = 0; i < obj->numWeapons; i++) { const objDef_t *weapon = obj->weapons[i]; if (weapon && weapon != obj && INV_ItemMatchesFilter(weapon, filterType)) return true; } break; case FILTER_S_HEAVY: if (obj->isHeavy) return true; /* Check if one of the items that uses this ammo matches this filter type. */ for (i = 0; i < obj->numWeapons; i++) { const objDef_t *weapon = obj->weapons[i]; if (weapon && weapon != obj && INV_ItemMatchesFilter(weapon, filterType)) return true; } break; case FILTER_S_ARMOUR: return obj->isArmour(); case FILTER_S_MISC: return obj->isMisc; case FILTER_CRAFTITEM: /** @todo Should we handle FILTER_AIRCRAFT here as well? */ return obj->isCraftItem(); case FILTER_UGVITEM: return obj->isUGVitem; case FILTER_DUMMY: return obj->isDummy; case FILTER_AIRCRAFT: return Q_streq(obj->type, "aircraft"); case FILTER_DISASSEMBLY: /** @todo I guess we should search for components matching this item here. */ break; case MAX_SOLDIER_FILTERTYPES: case MAX_FILTERTYPES: case FILTER_ENSURE_32BIT: Com_Printf("INV_ItemMatchesFilter: Unknown filter type for items: %i\n", filterType); break; } /* The given filter type is unknown. */ return false; }
/** * @return Alien mission category * @sa interestCategory_t */ static interestCategory_t CP_GetAlienMissionTypeByID (const char *type) { if (Q_streq(type, "recon")) return INTERESTCATEGORY_RECON; else if (Q_streq(type, "terror")) return INTERESTCATEGORY_TERROR_ATTACK; else if (Q_streq(type, "baseattack")) return INTERESTCATEGORY_BASE_ATTACK; else if (Q_streq(type, "building")) return INTERESTCATEGORY_BUILDING; else if (Q_streq(type, "supply")) return INTERESTCATEGORY_SUPPLY; else if (Q_streq(type, "xvi")) return INTERESTCATEGORY_XVI; else if (Q_streq(type, "intercept")) return INTERESTCATEGORY_INTERCEPT; else if (Q_streq(type, "harvest")) return INTERESTCATEGORY_HARVEST; else if (Q_streq(type, "alienbase")) return INTERESTCATEGORY_ALIENBASE; else if (Q_streq(type, "ufocarrier")) return INTERESTCATEGORY_UFOCARRIER; else if (Q_streq(type, "rescue")) return INTERESTCATEGORY_RESCUE; else { Com_Printf("CP_GetAlienMissionTypeByID: unknown alien mission category '%s'\n", type); return INTERESTCATEGORY_NONE; } }
/** * @brief Draw a model using UI model definition */ static void UI_DrawModelNodeWithUIModel (uiNode_t *node, const char *source, modelInfo_t *mi, uiModel_t *model) { qboolean autoScaleComputed = qfalse; vec3_t autoScale; vec3_t autoCenter; while (model) { /* no animation */ mi->frame = 0; mi->oldframe = 0; mi->backlerp = 0; assert(model->model); mi->model = R_FindModel(model->model); if (!mi->model) { model = model->next; continue; } mi->skin = model->skin; mi->name = model->model; /* set mi pointers to model */ mi->origin = model->origin; mi->angles = model->angles; mi->center = model->center; mi->color = model->color; mi->scale = model->scale; if (model->tag && model->parent) { /* tag and parent defined */ uiModel_t *parentModel; modelInfo_t pmi; vec3_t pmiorigin; animState_t *as; /* place this model part on an already existing model tag */ parentModel = UI_GetUIModel(model->parent); if (!parentModel) { Com_Printf("UI Model: Could not get the model '%s'\n", model->parent); break; } pmi.model = R_FindModel(parentModel->model); if (!pmi.model) { Com_Printf("UI Model: Could not get the model '%s'\n", parentModel->model); break; } pmi.name = parentModel->model; pmi.origin = pmiorigin; pmi.angles = parentModel->angles; pmi.scale = parentModel->scale; pmi.center = parentModel->center; pmi.color = parentModel->color; pmi.origin[0] = parentModel->origin[0] + mi->origin[0]; pmi.origin[1] = parentModel->origin[1] + mi->origin[1]; pmi.origin[2] = parentModel->origin[2]; /* don't count window offset twice for tagged models */ mi->origin[0] -= node->root->pos[0]; mi->origin[1] -= node->root->pos[1]; /* autoscale? */ if (EXTRADATA(node).autoscale) { if (!autoScaleComputed) Sys_Error("Wrong order of model nodes - the tag and parent model node must be after the base model node"); pmi.scale = autoScale; pmi.center = autoCenter; } as = &parentModel->animState; if (!as) Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", pmi.name, parentModel->anim); pmi.frame = as->frame; pmi.oldframe = as->oldframe; pmi.backlerp = as->backlerp; R_DrawModelDirect(mi, &pmi, model->tag); } else { /* no tag and no parent means - base model or single model */ const char *ref; UI_InitModelInfoView(node, mi, model); Vector4Copy(node->color, mi->color); /* compute the scale and center for the first model. * it think its the bigger of composite models. * All next elements use the same result */ if (EXTRADATA(node).autoscale) { if (!autoScaleComputed) { vec2_t size; size[0] = node->size[0] - node->padding; size[1] = node->size[1] - node->padding; R_ModelAutoScale(size, mi, autoScale, autoCenter); autoScaleComputed = qtrue; } else { mi->scale = autoScale; mi->center = autoCenter; } } /* get the animation given by node properties */ if (EXTRADATA(node).animation && *EXTRADATA(node).animation) { ref = UI_GetReferenceString(node, EXTRADATA(node).animation); /* otherwise use the standard animation from UI model definition */ } else ref = model->anim; /* only base models have animations */ if (ref && *ref) { animState_t *as = &model->animState; const char *anim = R_AnimGetName(as, mi->model); /* initial animation or animation change */ if (anim == NULL || !Q_streq(anim, ref)) R_AnimChange(as, mi->model, ref); else R_AnimRun(as, mi->model, cls.frametime * 1000); mi->frame = as->frame; mi->oldframe = as->oldframe; mi->backlerp = as->backlerp; } R_DrawModelDirect(mi, NULL, NULL); } /* next */ model = model->next; } }