From 0dc8f4ec757ae8c07d82e14489d0fb5ef60529e6 Mon Sep 17 00:00:00 2001 From: Marco Cawthorne Date: Wed, 14 Jun 2023 06:44:37 -0700 Subject: [PATCH] entityDef: add support for condition based tweaks --- src/server/entityDef.qc | 221 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 218 insertions(+), 3 deletions(-) diff --git a/src/server/entityDef.qc b/src/server/entityDef.qc index 48b6137c..6e4733ef 100644 --- a/src/server/entityDef.qc +++ b/src/server/entityDef.qc @@ -49,17 +49,32 @@ #define ENTITYDEF_MAX 128 #endif +var string g_lastSpawnData; + +enum +{ + EDEFTWEAK_EQ = 0, + EDEFTWEAK_LT, + EDEFTWEAK_GT, + EDEFTWEAK_NOT +}; + typedef struct { string entClass; string spawnClass; string spawnData; string inheritKeys; + + string tweakDefs; + string tweakKeys; } entityDef_t; entityDef_t g_entDefTable[ENTITYDEF_MAX]; var int g_entDefCount; +string g_entDefInclude; + void EntityDef_ReadFile(string filePath) { @@ -73,6 +88,8 @@ EntityDef_ReadFile(string filePath) currentDef.spawnClass = ""; currentDef.spawnData = ""; currentDef.inheritKeys = ""; + currentDef.tweakDefs = ""; + currentDef.tweakKeys = ""; /* bounds check */ if (g_entDefCount >= ENTITYDEF_MAX) { @@ -108,6 +125,8 @@ EntityDef_ReadFile(string filePath) g_entDefTable[g_entDefCount].spawnClass = currentDef.spawnClass; g_entDefTable[g_entDefCount].spawnData = currentDef.spawnData; g_entDefTable[g_entDefCount].inheritKeys = currentDef.inheritKeys; + g_entDefTable[g_entDefCount].tweakDefs = currentDef.tweakDefs; + g_entDefTable[g_entDefCount].tweakKeys = currentDef.tweakKeys; /* increment the def count */ if (g_entDefCount < ENTITYDEF_MAX) @@ -117,12 +136,23 @@ EntityDef_ReadFile(string filePath) currentDef.spawnClass = ""; currentDef.spawnData = ""; currentDef.inheritKeys = ""; + currentDef.tweakDefs = ""; + currentDef.tweakKeys = ""; + } + + /* we came out of a tweak */ + if (braceDepth == 1) { + if (currentDef.tweakDefs != "") { + currentDef.tweakKeys = strcat(currentDef.tweakKeys, ";"); /* mark the end of a key chain */ + } } break; default: /* anything outside braces defines the classname for the next def */ if (braceDepth == 0 && lastWord == "entityDef") { currentDef.entClass = word; + } else if (braceDepth == 0 && lastWord == "include") { + g_entDefInclude = strcat(g_entDefInclude, word, ";"); } else if (braceDepth == 1) { /* spawnclass is reserved and the next keyword specs it */ if (word == "spawnclass") { @@ -134,9 +164,57 @@ EntityDef_ReadFile(string filePath) } else if (substring(word, 0, 7) == "editor_") { /* do nothing */ i++; + } else if (substring(word, 0, 4) == "when") { + switch (argv(i+2)) { + case "equals": + currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 0 ", argv(i+3), ";"); + break; + case "less-than": + currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 1 ", argv(i+3), ";"); + break; + case "greater-than": + currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 2 ", argv(i+3), ";"); + break; + case "is-not": + currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 3 ", argv(i+3), ";"); + break; + + } + i+=3; } else { /* rest gets dumped into spawndata */ currentDef.spawnData = strcat(currentDef.spawnData, "\"", word, "\"", " "); } + } else if (braceDepth == 2) { + /* spawnclass is reserved and the next keyword specs it */ + if (word == "spawnclass") { + currentDef.spawnClass = argv(i+1); + i++; + } else if (word == "inherit") { + currentDef.inheritKeys = argv(i+1); + i++; + } else if (substring(word, 0, 7) == "editor_") { + /* do nothing */ + i++; + } else if (substring(word, 0, 4) == "when") { + switch (argv(i+2)) { + case "equals": + currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 0 ", argv(i+3), ";"); + break; + case "less-than": + currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 1 ", argv(i+3), ";"); + break; + case "greater-than": + currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 2 ", argv(i+3), ";"); + break; + case "is-not": + currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 3 ", argv(i+3), ";"); + break; + + } + i+=3; + } else { /* rest gets dumped into spawndata */ + currentDef.tweakKeys = strcat(currentDef.tweakKeys, "\"", word, "\"", " "); + } } } lastWord = word; @@ -151,19 +229,36 @@ void EntityDef_Init(void) { searchhandle pm; + + g_entDefInclude = ""; + pm = search_begin("def/*.def", TRUE, TRUE); for (int i = 0; i < search_getsize(pm); i++) { EntityDef_ReadFile(search_getfilename(pm, i)); } search_end(pm); + //print(sprintf("includes: %S\n", g_entDefInclude)); + + if (g_entDefInclude != "") { + int includeCount = tokenizebyseparator(g_entDefInclude, ";"); + + for (int i = 0; i < (includeCount-1); i++) { + string fileName = strcat("def/", argv(i)); + EntityDef_ReadFile(fileName); + includeCount = tokenizebyseparator(g_entDefInclude, ";"); + } + } + #if 0 for (int i = 0i; i < g_entDefCount; i++) { int numKeys = tokenize_console(g_entDefTable[i].spawnData); print(sprintf("edef %i: %S\n", i, g_entDefTable[i].entClass)); print(sprintf("\tspawnclass: %S\n", g_entDefTable[i].spawnClass)); print(sprintf("\tinheritKeys: %S\n", g_entDefTable[i].inheritKeys)); - print(sprintf("\tspawnData:\n", g_entDefTable[i].spawnData)); + print(sprintf("\ttweakDefs %S\n", g_entDefTable[i].tweakDefs)); + print(sprintf("\ttweakKeys %S\n", g_entDefTable[i].tweakKeys)); + print("\tspawnData:\n"); for (int c = 0; c < numKeys; c+=2) { print(sprintf("\t\t%S %S\n", argv(c), argv(c+1))); @@ -172,6 +267,54 @@ EntityDef_Init(void) #endif } +static bool +EntityDef_CheckCondition(int id, string keyWord, float tweakCondition, string keyValue) +{ + int spawnWords = tokenize_console(g_lastSpawnData); + string key, value; + float tmp1, tmp2; + + //print(sprintf("%i %S %d %S\n", id, keyWord, tweakCondition, keyValue)); + + for (int i = 1; i < (spawnWords - 1); i+= 2) { + key = argv(i); + value = argv(i+1); + + //print(sprintf("comparing %S with %S\n", key, value)); + + /* fforward out */ + if (key != keyWord) + continue; + + switch (tweakCondition) { + case EDEFTWEAK_EQ: + if (key == keyWord && value == keyValue) + return true; + break; + case EDEFTWEAK_LT: + tmp1 = stof(keyValue); + tmp2 = stof(value); + + if (key == keyWord && tmp2 < tmp1) + return true; + break; + case EDEFTWEAK_GT: + tmp1 = stof(keyValue); + tmp2 = stof(value); + + if (key == keyWord && tmp2 > tmp1) + return true; + break; + case EDEFTWEAK_NOT: + if (key == keyWord && value != keyValue) + return true; + break; + } + } + + return false; +} + static NSEntity EntityDef_PrepareEntity(entity target, int id) { @@ -226,27 +369,87 @@ EntityDef_PrepareEntity(entity target, int id) } /* now we load our own spawndata, which starts and ends with braces */ - spawnWords = tokenize_console(__fullspawndata); + spawnWords = tokenize_console(g_lastSpawnData); for (int i = 1; i < (spawnWords - 1); i+= 2) { /* ignore this, always */ if (argv(i) != "classname") targetEnt.SpawnKey(argv(i), argv(i+1)); } + + /* now after everything else is done, check our entityDef tweaks */ + spawnWords = tokenizebyseparator(g_entDefTable[id].tweakDefs, ";"); + for (int i = 0; i < spawnWords; i++) { + string groupSegment = argv(i); + + //print(sprintf("group: %S\n", groupSegment)); + tokenize_console(groupSegment); /* split the group segment into 3 */ + + string keyWord = argv(0); + float tweakCondition = stof(argv(1)); + string keyValue = argv(2); + + /* iterate through a bunch of different data to check our condition */ + if (EntityDef_CheckCondition(id, keyWord, tweakCondition, keyValue)) { + int tweakGroups = tokenizebyseparator(g_entDefTable[id].tweakKeys, ";"); + + //print(sprintf("%S passed the check\n", keyWord)); + + /* iterate through the ; key groups */ + for (int x = 0; x < tweakGroups; x++) { + int tweakSpawns = tokenize_console(argv(x)); + + /* ignore any other key group */ + if (x == i) { + /* iterate through key/value pairs within the ; key groups */ + for (int y = 0; y < tweakSpawns; y+= 2) { + //print(sprintf("applying %S and %S\n", argv(y), argv(y+1))); + targetEnt.SpawnKey(argv(y), argv(y+1)); + } + } + + /* retokenize */ + tweakGroups = tokenizebyseparator(g_entDefTable[id].tweakKeys, ";"); + } + } + + /* retokenize our condition */ + spawnWords = tokenizebyseparator(g_entDefTable[id].tweakDefs, ";"); + } + targetEnt.Spawned(); targetEnt.Respawn(); /* now we rename the classname for better visibility */ targetEnt.classname = g_entDefTable[id].entClass; - __fullspawndata = ""; + g_lastSpawnData = ""; return targetEnt; } +/* precache resources inside an entityDef */ +static void +EntityDef_Precaches(int index) +{ + int spawnWords = tokenize_console(g_entDefTable[index].spawnData); + for (int i = 0; i < spawnWords; i+= 2) { + string strKey = argv(i); + string strValue = argv(i+1); + + if (substring(strKey, 0, 4) == "snd_") { + Sound_Precache(strValue); + spawnWords = tokenize_console(g_entDefTable[index].spawnData); + } + } +} + NSEntity EntityDef_SpawnClassname(string className) { + g_lastSpawnData = __fullspawndata; + for (int i = 0i; i < g_entDefCount; i++) { if (className == g_entDefTable[i].entClass) { + EntityDef_Precaches(i); return EntityDef_PrepareEntity(self, i); } } @@ -304,4 +507,16 @@ EntityDef_GetKeyValue(string className, string keyName) } return ""; +} + +bool +EntityDef_HasSpawnClass(string className) +{ + for (int i = 0i; i < g_entDefCount; i++) { + if (className == g_entDefTable[i].entClass) { + return (g_entDefTable[i].spawnClass != "") ? true : false; + } + } + + return false; } \ No newline at end of file