diff --git a/include/g_local.h b/include/g_local.h index 5be51c44..4b9514f2 100644 --- a/include/g_local.h +++ b/include/g_local.h @@ -218,6 +218,9 @@ enum G_POINTPARTICLES, G_CLIENTSTAT, G_POINTERSTAT, + G_MAPEXTFIELDPTR, + G_SETEXTFIELDPTR, + G_GETEXTFIELDPTR, G_EXTENSIONS_LAST }; extern qbool haveextensiontab[G_EXTENSIONS_LAST-G_EXTENSIONS_FIRST]; @@ -519,6 +522,7 @@ void PlayerPostThink(void); qbool PlayerCanPause(gedict_t *p); void SuperDamageSound(void); +char *Spawn_GetModel(void); gedict_t* SelectSpawnPoint(char *spawnname); #define WP_STATS_UPDATE (0.3f) diff --git a/include/g_syscalls.h b/include/g_syscalls.h index cbda3d3b..65da7cd6 100644 --- a/include/g_syscalls.h +++ b/include/g_syscalls.h @@ -144,14 +144,16 @@ intptr_t trap_movetogoal(float dist); void trap_VisibleTo(intptr_t viewer, intptr_t first, intptr_t len, byte *visible); // Raw calls, use _i and _f helpers instead. -void trap_SetExtField(gedict_t *ed, const char *fieldname, int val); +void trap_SetExtField(gedict_t *ed, const char *fieldname, intptr_t val); int trap_GetExtField(gedict_t *ed, const char *fieldname); +intptr_t trap_MapExtFieldPtr(const char *fieldname); +intptr_t trap_SetExtFieldPtr(gedict_t *ed, intptr_t fieldref, intptr_t *data, intptr_t size); +intptr_t trap_GetExtFieldPtr(gedict_t *ed, intptr_t fieldref, intptr_t *data, intptr_t size); // Checks for server support before call -void trap_SetExtField_i(gedict_t *ed, const char *fieldname, int val); -void trap_SetExtField_f(gedict_t *ed, const char *fieldname, float val); -int trap_GetExtField_i(gedict_t *ed, const char *fieldname); -float trap_GetExtField_f(gedict_t *ed, const char *fieldname); +void ExtFieldSetAlpha(gedict_t *ed, float alpha); +float ExtFieldGetAlpha(gedict_t *ed); +void ExtFieldSetColorMod(gedict_t *ed, float r, float g, float b); void trap_changelevelHub(const char *name, const char *entityname, const char *startspot); int trap_URI_Query(const char *uri, int vmentry/*GAME_...*/, void *cbcontext, const char *mimetype, const char *data, size_t datasize); diff --git a/src/func_laser.c b/src/func_laser.c index 7ddd2203..5567df53 100644 --- a/src/func_laser.c +++ b/src/func_laser.c @@ -6,11 +6,11 @@ static void laser_helper_think(void) { gedict_t *owner = PROG_TO_EDICT(self->s.v.owner); - float alpha = trap_GetExtField_f(self, "alpha"); + float alpha = ExtFieldGetAlpha(self); if (!((int) owner->s.v.spawnflags & START_OFF)) { - trap_SetExtField_f(self, "alpha", alpha * 0.8f + alpha * g_random() * 0.4f); + ExtFieldSetAlpha(self, alpha * 0.8f + alpha * g_random() * 0.4f); } self->s.v.nextthink = g_globalvars.time + 0.05f; @@ -92,12 +92,12 @@ void SP_func_laser(void) self->s.v.movetype = MOVETYPE_NONE; } - alpha = trap_GetExtField_f(self, "alpha"); + alpha = ExtFieldGetAlpha(self); if (!alpha) { alpha = 0.5f; } - trap_SetExtField_f(self, "alpha", alpha); + ExtFieldSetAlpha(self, alpha); if (!self->dmg) { @@ -148,7 +148,7 @@ void SP_func_laser(void) helper->s.v.owner = EDICT_TO_PROG(self); helper->s.v.nextthink = g_globalvars.time + 2; - trap_SetExtField_f(helper, "alpha", alpha); + ExtFieldSetAlpha(helper, alpha); helper->think = (func_t) init_laser_noise; } diff --git a/src/g_main.c b/src/g_main.c index f697d954..32b95051 100644 --- a/src/g_main.c +++ b/src/g_main.c @@ -646,6 +646,9 @@ static qbool G_InitExtensions(void) {"pointparticles", G_POINTPARTICLES}, {"clientstat", G_CLIENTSTAT}, {"pointerstat", G_POINTERSTAT}, + {"MapExtFieldPtr", G_MAPEXTFIELDPTR}, + {"SetExtFieldPtr", G_SETEXTFIELDPTR}, + {"GetExtFieldPtr", G_GETEXTFIELDPTR}, }; int i; for (i = 0; i < sizeof(exttraps)/sizeof(exttraps[0]); i++) diff --git a/src/g_spawn.c b/src/g_spawn.c index 491fdea8..a50688ad 100644 --- a/src/g_spawn.c +++ b/src/g_spawn.c @@ -178,6 +178,8 @@ field_t fields[] = // trigger_heal { "heal_amount", FOFS(healamount), F_FLOAT }, +// Colorized entities in map + { "colormod" -1, F_VECTOR }, { NULL } }; @@ -626,30 +628,30 @@ static void G_ParseField(const char *key, const char *value, gedict_t *ent) case F_VECTOR: sscanf(value, "%f %f %f", &vec[0], &vec[1], &vec[2]); - ((float*)(b + f->ofs))[0] = vec[0]; - ((float*)(b + f->ofs))[1] = vec[1]; - ((float*)(b + f->ofs))[2] = vec[2]; - break; - - case F_INT: if (f->ofs >= 0) { - *(int*)(b + f->ofs) = atoi(value); + ((float*)(b + f->ofs))[0] = vec[0]; + ((float*)(b + f->ofs))[1] = vec[1]; + ((float*)(b + f->ofs))[2] = vec[2]; } - else + else if (!strcmp(f->name, "colormod")) { - trap_SetExtField_i(ent, key, atoi(value)); + ExtFieldSetColorMod(ent, vec[0], vec[1], vec[2]); } break; + case F_INT: + *(int*)(b + f->ofs) = atoi(value); + break; + case F_FLOAT: if (f->ofs >= 0) { *(float*)(b + f->ofs) = atof(value); } - else + else if (!strcmp(f->name, "alpha")) { - trap_SetExtField_f(ent, key, atof(value)); + ExtFieldSetAlpha(ent, atof(value)); } break; diff --git a/src/g_syscalls.asm b/src/g_syscalls.asm index 5e52fe9f..f4d178ed 100644 --- a/src/g_syscalls.asm +++ b/src/g_syscalls.asm @@ -116,3 +116,6 @@ equ trap_trailparticles -262 equ trap_pointparticles -263 equ trap_clientstat -264 equ trap_pointerstat -265 +equ trap_MapExtFieldPtr -266 +equ trap_SetExtFieldPtr -267 +equ trap_GetExtFieldPtr -268 diff --git a/src/g_syscalls.c b/src/g_syscalls.c index 8a4ea096..babcd72b 100644 --- a/src/g_syscalls.c +++ b/src/g_syscalls.c @@ -466,7 +466,22 @@ void trap_VisibleTo(intptr_t viewer, intptr_t first, intptr_t len, byte *visible syscall(G_VISIBLETO, viewer, first, len, (intptr_t) visible); } -void trap_SetExtField(gedict_t *ed, const char *fieldname, int val) +intptr_t trap_MapExtFieldPtr(const char *fieldname) +{ + return syscall(G_MAPEXTFIELDPTR, (intptr_t)fieldname); +} + +intptr_t trap_SetExtFieldPtr(gedict_t *ed, intptr_t fieldref, intptr_t *data, intptr_t size) +{ + return syscall(G_SETEXTFIELDPTR, (intptr_t)ed, fieldref, (intptr_t)data, size); +} + +intptr_t trap_GetExtFieldPtr(gedict_t *ed, intptr_t fieldref, intptr_t *data, intptr_t size) +{ + return syscall(G_GETEXTFIELDPTR, (intptr_t)ed, fieldref, (intptr_t)data, size); +} + +void trap_SetExtField(gedict_t *ed, const char *fieldname, intptr_t val) { syscall(G_SETEXTFIELD, (intptr_t)ed, (intptr_t)fieldname, val); } diff --git a/src/g_syscalls_extra.c b/src/g_syscalls_extra.c index e7818682..835ef5ba 100644 --- a/src/g_syscalls_extra.c +++ b/src/g_syscalls_extra.c @@ -4,52 +4,74 @@ typedef union fi_s { float _float; - intptr_t _int; + int _int; } fi_t; -void trap_SetExtField_i(gedict_t *ed, const char *fieldname, int val) +static unsigned int field_ref_alpha = 0; +static unsigned int field_ref_colormod = 0; + +void ExtFieldSetAlpha(gedict_t *ed, float alpha) { - if (HAVEEXTENSION(G_SETEXTFIELD)) + alpha = bound(0.0f, alpha, 1.0f); + if (!field_ref_alpha && HAVEEXTENSION(G_MAPEXTFIELDPTR) && HAVEEXTENSION(G_SETEXTFIELDPTR)) { - trap_SetExtField(ed, fieldname, val); + field_ref_alpha = trap_MapExtFieldPtr("alpha"); } - else + if (field_ref_alpha) { - G_bprint(PRINT_HIGH, "SetExtField(%s, %s, %d) not supported by server\n", ed->classname, fieldname, val); + trap_SetExtFieldPtr(ed, field_ref_alpha, (void*)&alpha, sizeof(float)); } -} - -void trap_SetExtField_f(gedict_t *ed, const char *fieldname, float val) -{ - if (HAVEEXTENSION(G_SETEXTFIELD)) + else if (HAVEEXTENSION(G_SETEXTFIELD)) { - fi_t rc; - rc._float = val; - trap_SetExtField(ed, fieldname, rc._int); + fi_t v; + v._float = alpha; + trap_SetExtField(ed, "alpha", v._int); } - else + else if (cvar("developer")) { - G_bprint(PRINT_HIGH, "SetExtField(%s, %s, %f) not supported by server\n", ed->classname, fieldname, val); + G_bprint(PRINT_HIGH, "alpha needs SetExtField or MapExtFieldPtr and SetExtFieldPtr support in server\n"); } } -int trap_GetExtField_i(gedict_t *ed, const char *fieldname) +float ExtFieldGetAlpha(gedict_t *ed) { - int ival = -1; - if (HAVEEXTENSION(G_GETEXTFIELD)) + fi_t tmp; + tmp._float = -1.0f; + if (!field_ref_alpha && HAVEEXTENSION(G_MAPEXTFIELDPTR) && HAVEEXTENSION(G_GETEXTFIELDPTR)) + { + field_ref_alpha = trap_MapExtFieldPtr("alpha"); + } + if (field_ref_alpha) + { + trap_GetExtFieldPtr(ed, field_ref_alpha, (void*)&tmp._float, sizeof(float)); + } + else if (HAVEEXTENSION(G_GETEXTFIELD)) { - ival = trap_GetExtField(ed, fieldname); + tmp._int = trap_GetExtField(ed, "alpha"); } - return ival; + else if (cvar("developer")) + { + G_bprint(PRINT_HIGH, "alpha needs GetExtField or MapExtFieldPtr and GetExtFieldPtr support in server\n"); + } + return tmp._float; } -float trap_GetExtField_f(gedict_t *ed, const char *fieldname) +void ExtFieldSetColorMod(gedict_t *ed, float r, float g, float b) { - fi_t tmp; - tmp._float = -1.0f; - if (HAVEEXTENSION(G_GETEXTFIELD)) + if (!field_ref_colormod && HAVEEXTENSION(G_MAPEXTFIELDPTR) && HAVEEXTENSION(G_SETEXTFIELDPTR)) { - tmp._int = trap_GetExtField(ed, fieldname); + field_ref_colormod = trap_MapExtFieldPtr("colormod"); + } + if (field_ref_colormod) + { + float rgb[3]; + rgb[0] = max(0.0f, r); + rgb[1] = max(0.0f, g); + rgb[2] = max(0.0f, b); + trap_SetExtFieldPtr(ed, field_ref_colormod, (void*)&rgb, sizeof(rgb)); + } + else if (cvar("developer")) + { + G_bprint(PRINT_HIGH, "colormod needs MapExtFieldPtr and SetExtFieldPtr support in server\n"); } - return tmp._float; } diff --git a/src/items.c b/src/items.c index 6f7c8507..7c47aa15 100644 --- a/src/items.c +++ b/src/items.c @@ -2868,21 +2868,70 @@ void DropBackpack(void) =============================================================================== */ +char *Spawn_GetModel(void) +{ + // Can't rely on cvar_string response for setmodel/precache_model so caching here + static char spawn_model[128]; + if (!spawn_model[0]) + { + char *mdl = cvar_string("k_spm_custom_model"); + if (!strcmp(mdl, "0") || strlen(mdl) == 0) + { + strlcpy(spawn_model, "progs/w_g_key.mdl", sizeof(spawn_model)); + } + else if (!strcmp(mdl, "1")) + { + strlcpy(spawn_model, "progs/wizard.mdl", sizeof(spawn_model)); + } + else + { + strlcpy(spawn_model, mdl, sizeof(spawn_model)); + } + } + return spawn_model; +} + gedict_t* Spawn_OnePoint(gedict_t *spawn_point, vec3_t org, int effects) { + unsigned int nargs; + char *color_tint; gedict_t *p; p = spawn(); p->s.v.flags = FL_ITEM; p->s.v.solid = SOLID_NOT; p->s.v.movetype = MOVETYPE_NONE; - setmodel(p, cvar("k_spm_custom_model") ? "progs/wizard.mdl" : "progs/w_g_key.mdl"); + + setmodel(p, Spawn_GetModel()); + p->netname = "Spawn Point"; p->classname = "spawnpoint"; p->k_lastspawn = spawn_point; p->s.v.effects = (int)p->s.v.effects | effects; + color_tint = cvar_string("k_spm_color_rgba"); + + trap_CmdTokenize(color_tint); + nargs = trap_CmdArgc(); + if (nargs >= 3) { + char argument[128]; + float r, g, b; + + trap_CmdArgv(0, argument, sizeof(argument)); + r = max(0.0f, atof(argument)); + trap_CmdArgv(1, argument, sizeof(argument)); + g = max(0.0f, atof(argument)); + trap_CmdArgv(2, argument, sizeof(argument)); + b = max(0.0f, atof(argument)); + ExtFieldSetColorMod(p, r, g, b); + + if (nargs == 4) { + trap_CmdArgv(3, argument, sizeof(argument)); + ExtFieldSetAlpha(p, atof(argument)); + } + } + // store references for changing selections in hoonymode spawn_point->wizard = p; p->wizard = spawn_point; diff --git a/src/world.c b/src/world.c index 977f8f19..2af744a4 100644 --- a/src/world.c +++ b/src/world.c @@ -330,10 +330,7 @@ void SP_worldspawn(void) trap_precache_sound("ambience/windfly.wav"); - if (cvar("k_spm_custom_model")) - { - trap_precache_model("progs/spawn.mdl"); - } + trap_precache_model(Spawn_GetModel()); trap_precache_model("progs/player.mdl"); @@ -869,6 +866,7 @@ void FirstFrame(void) RegisterCvarEx("k_spm_show", "1"); RegisterCvarEx("k_spm_glow", "0"); RegisterCvarEx("k_spm_custom_model", "0"); + RegisterCvarEx("k_spm_color_rgba", "1.0 1.0 1.0 1.0"); RegisterCvar("k_entityfile"); // { hoonymode RegisterCvarEx("k_hoonymode", "0");