/** * Parse a string according to a property type, and allocate a raw value to the static memory * * @param action Action to initialize * @param node Current node we are parsing, only used for error message * @param property Type of the value to parse, if nullptr the string is not stored as string * @param string String value to parse * @return True if the action is initialized * @todo remove node param and catch error where we call that function */ bool UI_InitRawActionValue (uiAction_t* action, uiNode_t* node, const value_t* property, const char* string) { if (property == nullptr) { action->type = EA_VALUE_STRING; action->d.terminal.d1.data = UI_AllocStaticString(string, 0); action->d.terminal.d2.integer = 0; return true; } if (property->type == V_UI_SPRITEREF) { uiSprite_t* sprite = UI_GetSpriteByName(string); if (sprite == nullptr) { Com_Printf("UI_ParseSetAction: sprite '%s' not found (%s)\n", string, UI_GetPath(node)); return false; } action->type = EA_VALUE_RAW; action->d.terminal.d1.data = sprite; action->d.terminal.d2.integer = property->type; return true; } else { const int baseType = property->type & V_UI_MASK; if (baseType != 0 && baseType != V_UI_CVAR) { Com_Printf("UI_ParseRawValue: setter for property '%s' (type %d, 0x%X) is not supported (%s)\n", property->string, property->type, property->type, UI_GetPath(node)); return false; } ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t) (property->type & V_BASETYPEMASK)); action->type = EA_VALUE_RAW; action->d.terminal.d1.data = ui_global.curadata; action->d.terminal.d2.integer = property->type; /** @todo we should hide use of ui_global.curadata */ ui_global.curadata += Com_EParseValue(ui_global.curadata, string, (valueTypes_t) (property->type & V_BASETYPEMASK), 0, property->size); return true; } }
static bool UI_ParseExcludeRect (uiNode_t* node, const char** text, const char** token, const char* errhead) { uiExcludeRect_t rect; uiExcludeRect_t* newRect; /* get parameters */ *token = Com_EParse(text, errhead, node->name); if (!*text) return false; if ((*token)[0] != '{') { Com_Printf("UI_ParseExcludeRect: node with bad excluderect ignored (node \"%s\")\n", UI_GetPath(node)); return true; } do { *token = Com_EParse(text, errhead, node->name); if (!*text) return false; /** @todo move it into a property array */ if (Q_streq(*token, "pos")) { *token = Com_EParse(text, errhead, node->name); if (!*text) return false; Com_EParseValue(&rect, *token, V_POS, offsetof(uiExcludeRect_t, pos), sizeof(vec2_t)); } else if (Q_streq(*token, "size")) { *token = Com_EParse(text, errhead, node->name); if (!*text) return false; Com_EParseValue(&rect, *token, V_POS, offsetof(uiExcludeRect_t, size), sizeof(vec2_t)); } } while ((*token)[0] != '}'); newRect = (uiExcludeRect_t*) UI_AllocHunkMemory(sizeof(*newRect), STRUCT_MEMORY_ALIGN, false); if (newRect == nullptr) { Com_Printf("UI_ParseExcludeRect: ui hunk memory exceeded."); return false; } /* move data to final memory and link to node */ *newRect = rect; newRect->next = node->firstExcludeRect; node->firstExcludeRect = newRect; return true; }
void GAME_ParseModes (const char *name, const char **text) { const char *errhead = "GAME_ParseModes: unexpected end of file (cgame "; cgameType_t *ed; const char *token; const value_t *vp; int i; /* search for equipments with same name */ for (i = 0; i < numCGameTypes; i++) if (Q_streq(name, cgameTypes[i].id)) break; if (i < numCGameTypes) { Com_Printf("GAME_ParseModes: cgame def \"%s\" with same name found, second ignored\n", name); return; } if (i >= MAX_CGAMETYPES) Sys_Error("GAME_ParseModes: MAX_CGAMETYPES exceeded\n"); /* initialize the equipment definition */ ed = &cgameTypes[numCGameTypes++]; OBJZERO(*ed); Q_strncpyz(ed->id, name, sizeof(ed->id)); /* get it's body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("GAME_ParseModes: cgame def \"%s\" without body ignored\n", name); numCGameTypes--; return; } do { token = Com_EParse(text, errhead, name); if (!*text || *token == '}') return; for (vp = cgame_vals; vp->string; vp++) if (Q_streq(token, vp->string)) { /* found a definition */ token = Com_EParse(text, errhead, name); if (!*text) return; Com_EParseValue(ed, token, vp->type, vp->ofs, vp->size); break; } if (!vp->string) { Sys_Error("unknown token in cgame definition %s: '%s'", ed->id, token); } } while (*text); }
/** * @brief Parses particle used on maps. * @param[in,out] ptl Pointer to particle being parsed and updated. * @param[in] es Entity string to parse the particle from * @param[in] afterwards If this is true you can modify the particle after the init * function for the particle was already called */ static void CL_ParseMapParticle (ptl_t *ptl, const char *es, bool afterwards) { char keyname[MAX_VAR]; const char *token; char *key; const value_t *pp; key = keyname + 1; do { /* get keyname */ token = Com_Parse(&es); if (token[0] == '}') break; if (!es) Com_Error(ERR_DROP, "CL_ParseMapParticle: EOF without closing brace"); Q_strncpyz(keyname, token, sizeof(keyname)); /* parse value */ token = Com_Parse(&es); if (!es) Com_Error(ERR_DROP, "CL_ParseMapParticle: EOF without closing brace"); if (token[0] == '}') Com_Error(ERR_DROP, "CL_ParseMapParticle: closing brace without data"); if (!afterwards && keyname[0] != '-') continue; if (afterwards && keyname[0] != '+') continue; for (pp = pps; pp->string; pp++) { if (Q_streq(key, pp->string)) { /* found a normal particle value */ Com_EParseValue(ptl, token, pp->type, pp->ofs, pp->size); break; } } if (!pp->string) { /* register art */ if (Q_streq(key, "image")) ptl->pic = CL_ParticleGetArt(token, ptl->frame, ART_PIC); else if (Q_streq(key, "model")) ptl->model = CL_ParticleGetArt(token, ptl->frame, ART_MODEL); else if (Q_streq(key, "program")) { ptl->program = R_LoadProgram(token, R_InitParticleProgram, R_UseParticleProgram); if (ptl->program) ptl->program->userdata = ptl; } } } while (token); }
/** * @brief Parse 2D objects like text and images * @return 1 - increase the command position of the sequence by one * @sa seq2D_vals * @sa CL_SequenceFind2D */ static int SEQ_ExecuteObj2D (sequenceContext_t *context, const char *name, const char *data) { seq2D_t *s2d; const value_t *vp; int i; /* get sequence text */ s2d = SEQ_Find2D(context, name); if (!s2d) { /* create new sequence text */ for (i = 0, s2d = context->obj2Ds; i < context->numObj2Ds; i++, s2d++) if (!s2d->inuse) break; if (i >= context->numObj2Ds) { if (context->numObj2Ds >= MAX_SEQ2DS) Com_Error(ERR_FATAL, "Too many sequence 2d objects"); s2d = &context->obj2Ds[context->numObj2Ds++]; } /* allocate */ OBJZERO(*s2d); for (i = 0; i < 4; i++) s2d->color[i] = 1.0f; s2d->inuse = true; Q_strncpyz(s2d->font, "f_big", sizeof(s2d->font)); /* default font */ Q_strncpyz(s2d->name, name, sizeof(s2d->name)); } /* get values */ while (*data) { for (vp = seq2D_vals; vp->string; vp++) if (Q_streq(data, vp->string)) { data += strlen(data) + 1; switch (vp->type) { case V_TRANSLATION_STRING: data++; case V_HUNK_STRING: Mem_PoolStrDupTo(data, &Com_GetValue<char*>(s2d, vp), cl_genericPool, 0); break; default: Com_EParseValue(s2d, data, vp->type, vp->ofs, vp->size); break; } break; } if (!vp->string) Com_Printf("SEQ_ExecuteObj2D: unknown token '%s'\n", data); data += strlen(data) + 1; } return 1; }
/** * @brief Parse values for a sequence model * @return 1 - increase the command position of the sequence by one * @sa seqEnt_vals * @sa CL_SequenceFindEnt */ static int SEQ_ExecuteModel (sequenceContext_t *context, const char *name, const char *data) { /* get sequence entity */ seqEnt_t *se = SEQ_FindEnt(context, name); if (!se) { int i; /* create new sequence entity */ for (i = 0, se = context->ents; i < context->numEnts; i++, se++) if (!se->inuse) break; if (i >= context->numEnts) { if (context->numEnts >= MAX_SEQENTS) Com_Error(ERR_FATAL, "Too many sequence entities"); se = &context->ents[context->numEnts++]; } /* allocate */ OBJZERO(*se); se->inuse = true; Q_strncpyz(se->name, name, sizeof(se->name)); VectorSet(se->color, 0.7, 0.7, 0.7); } /* get values */ while (*data) { const value_t *vp; for (vp = seqEnt_vals; vp->string; vp++) if (Q_streq(data, vp->string)) { data += strlen(data) + 1; Com_EParseValue(se, data, vp->type, vp->ofs, vp->size); break; } if (!vp->string) { if (Q_streq(data, "model")) { data += strlen(data) + 1; Com_DPrintf(DEBUG_CLIENT, "Registering model: %s\n", data); se->model = R_FindModel(data); if (se->model == NULL) se->inuse = false; } else if (Q_streq(data, "anim")) { if (se->model == NULL) Com_Error(ERR_FATAL, "could not change the animation - no model loaded yet"); data += strlen(data) + 1; Com_DPrintf(DEBUG_CLIENT, "Change anim to: %s\n", data); R_AnimChange(&se->as, se->model, data); } else Com_Printf("SEQ_ExecuteModel: unknown token '%s'\n", data); } data += strlen(data) + 1; } return 1; }
/** * @brief Parse the values for the camera like given in seqCamera */ static int SEQ_ExecuteCamera (sequenceContext_t *context, const char *name, const char *data) { /* get values */ while (*data) { const value_t *vp; for (vp = seqCamera_vals; vp->string; vp++) if (Q_streq(data, vp->string)) { data += strlen(data) + 1; Com_EParseValue(&context->camera, data, vp->type, vp->ofs, vp->size); break; } if (!vp->string) Com_Printf("SEQ_ExecuteCamera: unknown token '%s'\n", data); data += strlen(data) + 1; } return 1; }
/** * @brief parses the models.ufo and all files where UI models (menu_model) are defined * @sa CL_ParseClientData */ bool UI_ParseUIModel (const char* name, const char** text) { const char* errhead = "UI_ParseUIModel: unexpected end of file (names "; /* search for a UI models with same name */ for (int i = 0; i < ui_global.numModels; i++) if (Q_streq(ui_global.models[i].id, name)) { Com_Printf("UI_ParseUIModel: menu_model \"%s\" with same name found, second ignored\n", name); return false; } if (ui_global.numModels >= UI_MAX_MODELS) { Com_Printf("UI_ParseUIModel: Max UI models reached\n"); return false; } /* initialize the model */ uiModel_t* model = &ui_global.models[ui_global.numModels]; OBJZERO(*model); Vector4Set(model->color, 1, 1, 1, 1); model->id = Mem_PoolStrDup(name, ui_sysPool, 0); Com_DPrintf(DEBUG_CLIENT, "Found UI model %s (%i)\n", model->id, ui_global.numModels); /* get it's body */ const char* token = Com_Parse(text); if (!*text || token[0] != '{') { Com_Printf("UI_ParseUIModel: Model \"%s\" without body ignored\n", model->id); return false; } ui_global.numModels++; do { const value_t* v = nullptr; /* get the name type */ token = Com_EParse(text, errhead, name); if (!*text) return false; if (token[0] == '}') break; v = UI_FindPropertyByName(uiModelProperties, token); if (!v) { Com_Printf("UI_ParseUIModel: unknown token \"%s\" ignored (UI model %s)\n", token, name); return false; } if (v->type == V_NULL) { if (Q_streq(v->string, "need")) { token = Com_EParse(text, errhead, name); if (!*text) return false; if (model->next != nullptr) Sys_Error("UI_ParseUIModel: second 'need' token found in model %s", name); model->next = UI_GetUIModel(token); if (!model->next) Com_Printf("Could not find UI model %s", token); } } else { token = Com_EParse(text, errhead, name); if (!*text) return false; switch (v->type) { case V_HUNK_STRING: Mem_PoolStrDupTo(token, &Com_GetValue<char*>(model, v), ui_sysPool, 0); break; default: Com_EParseValue(model, token, v->type, v->ofs, v->size); break; } } } while (*text); return true; }
/** * @brief Parse the map entity string and spawns those entities that are client-side only * @sa G_SendEdictsAndBrushModels * @sa CL_AddBrushModel */ void CL_SpawnParseEntitystring (void) { const char *es = cl.mapData->mapEntityString; int entnum = 0, maxLevel; if (cl.mapMaxLevel > 0 && cl.mapMaxLevel < PATHFINDING_HEIGHT) maxLevel = cl.mapMaxLevel; else maxLevel = PATHFINDING_HEIGHT; /* vid restart? */ if (cl.numMapParticles || cl.numLMs) return; OBJZERO(sun); /* parse ents */ while (1) { localEntityParse_t entData; /* parse the opening brace */ const char *entityToken = Com_Parse(&es); /* memorize the start */ if (!es) break; if (entityToken[0] != '{') Com_Error(ERR_DROP, "V_ParseEntitystring: found %s when expecting {", entityToken); /* initialize */ OBJZERO(entData); VectorSet(entData.scale, 1, 1, 1); entData.volume = SND_VOLUME_DEFAULT; entData.maxLevel = maxLevel; entData.entStringPos = es; entData.entnum = entnum; entData.maxMultiplayerTeams = TEAM_MAX_HUMAN; entData.attenuation = SOUND_ATTN_IDLE; /* go through all the dictionary pairs */ while (1) { const value_t *v; /* parse key */ entityToken = Com_Parse(&es); if (entityToken[0] == '}') break; if (!es) Com_Error(ERR_DROP, "V_ParseEntitystring: EOF without closing brace"); for (v = localEntityValues; v->string; v++) if (Q_streq(entityToken, v->string)) { /* found a definition */ entityToken = Com_Parse(&es); if (!es) Com_Error(ERR_DROP, "V_ParseEntitystring: EOF without closing brace"); Com_EParseValue(&entData, entityToken, v->type, v->ofs, v->size); break; } } CL_SpawnCall(&entData); entnum++; } /* add the appropriate directional source to the list of active light sources*/ R_AddLightsource(&sun); /* after we have parsed all the entities we can resolve the target, targetname * connections for the misc_model entities */ LM_Think(); }
/** * @sa CL_ParseClientData */ bool UI_ParseFont (const char* name, const char** text) { const char* errhead = "UI_ParseFont: unexpected end of file (font"; /* search for font with same name */ if (UI_GetFontByID(name)) { Com_Printf("UI_ParseFont: font \"%s\" with same name found, second ignored\n", name); return false; } if (numFonts >= MAX_FONTS) { Com_Printf("UI_ParseFont: Max fonts reached\n"); return false; } /* initialize the UI */ uiFont_t* font = &fonts[numFonts]; OBJZERO(*font); font->name = Mem_PoolStrDup(name, ui_sysPool, 0); Com_DPrintf(DEBUG_CLIENT, "...found font %s (%i)\n", font->name, numFonts); /* get it's body */ const char* token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("UI_ParseFont: font \"%s\" without body ignored\n", name); return false; } numFonts++; do { /* get the name type */ token = Com_EParse(text, errhead, name); if (!*text) return false; if (*token == '}') break; const value_t* v; for (v = fontValues; v->string; v++) if (Q_streq(token, v->string)) { /* found a definition */ token = Com_EParse(text, errhead, name); if (!*text) return false; switch (v->type) { case V_TRANSLATION_STRING: token++; case V_HUNK_STRING: Mem_PoolStrDupTo(token, &Com_GetValue<char*>(font, v), ui_sysPool, 0); break; default: Com_EParseValue(font, token, v->type, v->ofs, v->size); break; } break; } if (!v->string) Com_Printf("UI_ParseFont: unknown token \"%s\" ignored (font %s)\n", token, name); } while (*text); UI_RegisterFont(font); return true; }
static void CL_ParsePtlCmds (const char *name, const char **text) { ptlCmd_t *pc; const value_t *pp; const char *errhead = "CL_ParsePtlCmds: unexpected end of file"; const char *token; int i, j; /* get it's body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("CL_ParsePtlCmds: particle cmds \"%s\" without body ignored\n", name); return; } do { token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; for (i = 0; i < PC_NUM_PTLCMDS; i++) if (Q_streq(token, pc_strings[i])) { /* allocate an new cmd */ if (numPtlCmds >= MAX_PTLCMDS) Com_Error(ERR_DROP, "CL_ParsePtlCmds: MAX_PTLCMDS exceeded"); pc = &ptlCmd[numPtlCmds++]; OBJZERO(*pc); pc->cmd = i; if (!pc_types[i]) break; /* get parameter type */ token = Com_EParse(text, errhead, name); if (!*text) return; /* operate on the top element on the stack */ if (token[0] == '#') { pc->ref = RSTACK; if (token[1] == '.') pc->ref -= (token[2] - '0'); break; } if (token[0] == '*') { int len; char baseComponentToken[MAX_VAR]; /* it's a variable reference */ token++; /* we maybe have to modify it */ Q_strncpyz(baseComponentToken, token, sizeof(baseComponentToken)); /* check for component specifier */ len = strlen(baseComponentToken); /* it's possible to change only the second value of e.g. a vector * just defined e.g. 'size.2' to modify the second value of size */ if (len >= 2 && baseComponentToken[len - 2] == '.') { baseComponentToken[len - 2] = 0; } else len = 0; for (pp = pps; pp->string; pp++) if (Q_streq(baseComponentToken, pp->string)) break; if (!pp->string) { Com_Printf("CL_ParsePtlCmds: bad reference \"%s\" specified (particle %s)\n", token, name); numPtlCmds--; break; } if ((pc_types[i] & PTL_ONLY_ONE_TYPE)) { if ((pc_types[i] & ~PTL_ONLY_ONE_TYPE) != pp->type) { Com_Printf("CL_ParsePtlCmds: bad type in var \"%s\" (PTL_ONLY_ONE_TYPE) specified (particle %s) (ptl type: %i (pc_type: %i), string: %s)\n", token, name, pp->type, pc_types[i], pc_strings[i]); numPtlCmds--; break; } } else if (pp->type >= V_NUM_TYPES || !((1 << pp->type) & pc_types[i])) { Com_Printf("CL_ParsePtlCmds: bad type in var \"%s\" specified (particle %s) (ptl type: %i (pc_type: %i), string: %s)\n", token, name, pp->type, pc_types[i], pc_strings[i]); numPtlCmds--; break; } if (len) { /* get single component */ if ((1 << pp->type) & V_VECS) { const int component = (baseComponentToken[len - 1] - '1'); /* get the component we want to modify */ if (component > 3) { Com_Printf("CL_ParsePtlCmds: bad component value - it's bigger than 3: %i (particle %s)\n", component, name); numPtlCmds--; break; } pc->type = V_FLOAT; /* go to component offset */ pc->ref = -((int)pp->ofs) - component * sizeof(float); break; } else { Com_Printf("CL_ParsePtlCmds: can't get components of a non-vector type (particle %s)\n", name); numPtlCmds--; break; } } /* set the values */ pc->type = pp->type; pc->ref = -((int)pp->ofs); break; } /* get the type */ if (pc_types[i] & PTL_ONLY_ONE_TYPE) /* extract the real type */ j = pc_types[i] & ~PTL_ONLY_ONE_TYPE; else { for (j = 0; j < V_NUM_TYPES; j++) if (Q_streq(token, vt_names[j])) break; if (j >= V_NUM_TYPES || !((1 << j) & pc_types[i])) { Com_Printf("CL_ParsePtlCmds: bad type \"%s\" specified (particle %s)\n", token, name); numPtlCmds--; break; } /* get the value */ token = Com_EParse(text, errhead, name); if (!*text) return; } /* set the values */ pc->type = j; pcmdPos = (byte*) Com_AlignPtr(pcmdPos, (valueTypes_t)pc->type); pc->ref = (int) (pcmdPos - pcmdData); pcmdPos += Com_EParseValue(pcmdPos, token, (valueTypes_t)pc->type, 0, 0); /* Com_Printf("%s %s %i\n", vt_names[pc->type], token, pcmdPos - pc->ref, (char *)pc->ref); */ break; } if (i < PC_NUM_PTLCMDS) continue; for (pp = pps; pp->string; pp++) if (Q_streq(token, pp->string)) { /* get parameter */ token = Com_EParse(text, errhead, name); if (!*text) return; /* translate set to a push and pop */ if (numPtlCmds >= MAX_PTLCMDS - 1) Com_Error(ERR_DROP, "CL_ParsePtlCmds: MAX_PTLCMDS exceeded"); pc = &ptlCmd[numPtlCmds++]; pc->cmd = PC_PUSH; pc->type = pp->type; pcmdPos = (byte*) Com_AlignPtr(pcmdPos, (valueTypes_t)pc->type); pc->ref = (int) (pcmdPos - pcmdData); pcmdPos += Com_EParseValue(pcmdPos, token, (valueTypes_t)pc->type, 0, 0); pc = &ptlCmd[numPtlCmds++]; pc->cmd = PC_POP; pc->type = pp->type; pc->ref = -((int)pp->ofs); break; } if (!pp->string) Com_Printf("CL_ParsePtlCmds: unknown token \"%s\" ignored (particle %s)\n", token, name); } while (*text); /* terminalize cmd chain */ if (numPtlCmds >= MAX_PTLCMDS) Com_Error(ERR_DROP, "CL_ParsePtlCmds: MAX_PTLCMDS exceeded"); pc = &ptlCmd[numPtlCmds++]; OBJZERO(*pc); }