Skip to content

Commit

Permalink
Add support for cursorhints in set/delete script actions (#1584)
Browse files Browse the repository at this point in the history
This required special handling as cursorhints are written as strings by mappers, but are internally mapped into an enum value.
  • Loading branch information
Aciz authored Dec 31, 2024
1 parent c8e75e0 commit 7a06fe2
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 68 deletions.
27 changes: 27 additions & 0 deletions src/game/bg_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -1891,6 +1891,33 @@ typedef enum {
HINT_NUM_HINTS
} hintType_t;

static constexpr std::array<const char *, HINT_NUM_HINTS + 1> hintStrings = {
"", // HINT_NONE
"HINT_NONE", // actually HINT_FORCENONE, but since this is being specified
// in the ent, the designer actually means HINT_FORCENONE
"HINT_PLAYER", "HINT_ACTIVATE", "HINT_DOOR", "HINT_DOOR_ROTATING",
"HINT_DOOR_LOCKED", "HINT_DOOR_ROTATING_LOCKED", "HINT_MG42",
"HINT_BREAKABLE", "HINT_BREAKABLE_BIG", "HINT_CHAIR", "HINT_ALARM",
"HINT_HEALTH", "HINT_TREASURE", "HINT_KNIFE", "HINT_LADDER", "HINT_BUTTON",
"HINT_WATER", "HINT_CAUTION", "HINT_DANGER", "HINT_SECRET", "HINT_QUESTION",
"HINT_EXCLAMATION", "HINT_CLIPBOARD", "HINT_WEAPON", "HINT_AMMO",
"HINT_ARMOR", "HINT_POWERUP", "HINT_HOLDABLE", "HINT_INVENTORY",
"HINT_SCENARIC", "HINT_EXIT", "HINT_NOEXIT", "HINT_PLYR_FRIEND",
"HINT_PLYR_NEUTRAL", "HINT_PLYR_ENEMY", "HINT_PLYR_UNKNOWN",
"HINT_BUILD", // DHM - Nerve
"HINT_DISARM", // DHM - Nerve
"HINT_REVIVE", // DHM - Nerve
"HINT_DYNAMITE", // DHM - Nerve

"HINT_CONSTRUCTIBLE", "HINT_UNIFORM", "HINT_LANDMINE", "HINT_TANK",
"HINT_SATCHELCHARGE",
// START Mad Doc - TDF
"HINT_LOCKPICK",
// END Mad Doc - TDF

"", // HINT_BAD_USER
};

void BG_EvaluateTrajectory(const trajectory_t *tr, int atTime, vec3_t result,
qboolean isAngle, int splinePath);
void BG_EvaluateTrajectoryDelta(const trajectory_t *tr, int atTime,
Expand Down
11 changes: 11 additions & 0 deletions src/game/etj_entity_utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

#include "etj_entity_utilities.h"
#include "etj_string_utilities.h"

namespace ETJump {
bool EntityUtilities::isPlayer(gentity_t *ent) {
Expand Down Expand Up @@ -124,4 +125,14 @@ bool EntityUtilities::entitiesFree(const int threshold) {

return free > threshold;
}

void EntityUtilities::setCursorhintFromString(int &value,
const std::string &hint) {
for (int i = 0; i < HINT_NUM_HINTS; i++) {
if (StringUtil::iEqual(hint, hintStrings[i])) {
value = i;
}
}
}

} // namespace ETJump
4 changes: 4 additions & 0 deletions src/game/etj_entity_utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,9 @@ class EntityUtilities {

// 'threshold' indicates the number of entities that must be free
static bool entitiesFree(int threshold);

// sets 'value' to corresponding cursorhint from 'hint'
// if 'hint' isn't found in hintStrings, no modification is performed
static void setCursorhintFromString(int &value, const std::string &hint);
};
} // namespace ETJump
3 changes: 2 additions & 1 deletion src/game/g_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ typedef enum {
F_ENTITY, // index on disk, pointer in memory
F_ITEM, // index on disk, pointer in memory
F_CLIENT, // index on disk, pointer in memory
F_IGNORE
F_IGNORE,
F_CURSORHINT, // maps cursorhint string to a correct int
} fieldtype_t;

typedef struct {
Expand Down
60 changes: 7 additions & 53 deletions src/game/g_mover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,6 @@
#include "etj_utilities.h"
#include "etj_entity_utilities.h"

static constexpr std::array<const char *, HINT_NUM_HINTS + 1> hintStrings = {
"", // HINT_NONE
"HINT_NONE", // actually HINT_FORCENONE, but since this is being specified
// in the ent, the designer actually means HINT_FORCENONE
"HINT_PLAYER", "HINT_ACTIVATE", "HINT_DOOR", "HINT_DOOR_ROTATING",
"HINT_DOOR_LOCKED", "HINT_DOOR_ROTATING_LOCKED", "HINT_MG42",
"HINT_BREAKABLE", "HINT_BREAKABLE_BIG", "HINT_CHAIR", "HINT_ALARM",
"HINT_HEALTH", "HINT_TREASURE", "HINT_KNIFE", "HINT_LADDER", "HINT_BUTTON",
"HINT_WATER", "HINT_CAUTION", "HINT_DANGER", "HINT_SECRET", "HINT_QUESTION",
"HINT_EXCLAMATION", "HINT_CLIPBOARD", "HINT_WEAPON", "HINT_AMMO",
"HINT_ARMOR", "HINT_POWERUP", "HINT_HOLDABLE", "HINT_INVENTORY",
"HINT_SCENARIC", "HINT_EXIT", "HINT_NOEXIT", "HINT_PLYR_FRIEND",
"HINT_PLYR_NEUTRAL", "HINT_PLYR_ENEMY", "HINT_PLYR_UNKNOWN",
"HINT_BUILD", // DHM - Nerve
"HINT_DISARM", // DHM - Nerve
"HINT_REVIVE", // DHM - Nerve
"HINT_DYNAMITE", // DHM - Nerve

"HINT_CONSTRUCTIBLE", "HINT_UNIFORM", "HINT_LANDMINE", "HINT_TANK",
"HINT_SATCHELCHARGE",
// START Mad Doc - TDF
"HINT_LOCKPICK",
// END Mad Doc - TDF

"", // HINT_BAD_USER
};

/*
===============================================================================
Expand Down Expand Up @@ -2699,11 +2672,8 @@ void SP_func_button(gentity_t *ent) {
ent->s.dmgFlags = HINT_BUTTON;

if (G_SpawnString("cursorhint", "0", &cursorhint)) {
for (int i = 0; i < HINT_NUM_HINTS; i++) {
if (!Q_stricmp(cursorhint, hintStrings[i])) {
ent->s.dmgFlags = i;
}
}
ETJump::EntityUtilities::setCursorhintFromString(ent->s.dmgFlags,
cursorhint);
}

// first position
Expand Down Expand Up @@ -4346,22 +4316,12 @@ void SP_func_explosive(gentity_t *ent) {
}
}

//----(SA) added

ent->s.dmgFlags = 0;
ent->s.dmgFlags = HINT_NONE;

if (G_SpawnString("cursorhint", "0", &cursorhint)) {

for (i = 0; i < HINT_NUM_HINTS; i++) {
if (!Q_stricmp(cursorhint, hintStrings[i])) {
ent->s.dmgFlags = i;
}
}
ETJump::EntityUtilities::setCursorhintFromString(ent->s.dmgFlags,
cursorhint);
}
//----(SA) end

// (SA) shouldn't need this
// ent->s.density = ent->count; // pass the "mass" to the client

ent->die = func_explosive_explode;
}
Expand Down Expand Up @@ -4506,16 +4466,10 @@ void SP_func_invisible_user(gentity_t *ent) {

ent->use = use_invisible_user;

//----(SA) added
if (G_SpawnString("cursorhint", "0", &cursorhint)) {

for (i = 0; i < HINT_NUM_HINTS; i++) {
if (!Q_stricmp(cursorhint, hintStrings[i])) {
ent->s.dmgFlags = i;
}
}
ETJump::EntityUtilities::setCursorhintFromString(ent->s.dmgFlags,
cursorhint);
}
//----(SA) end

if (!(ent->spawnflags &
static_cast<int>(ETJump::FuncInvisSpawnflags::NoOffNoise))) {
Expand Down
19 changes: 19 additions & 0 deletions src/game/g_script_actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// Tab Size: 4 (real tabs)
//===========================================================================

#include "etj_entity_utilities.h"
#include "../game/g_local.h"
#include "../game/q_shared.h"
#include "etj_printer.h"
Expand Down Expand Up @@ -4785,6 +4786,24 @@ qboolean G_ScriptAction_Delete(gentity_t *ent, char *params) {
ETJump::stringFormat(R"(%s "%s")", key, value));
}

break;
case F_CURSORHINT:
if (args.size() != 1) {
invalidArgCount(1, args.size());
break;
}

// set to end cap initially, so we don't delete all entities
// with HINT_NONE if we don't find a match
valueInt = HINT_NUM_HINTS;
ETJump::EntityUtilities::setCursorhintFromString(valueInt, value);

while ((found = G_FindInt(found, fields[i].ofs, valueInt)) != nullptr) {
pass[found->s.number].first++;
pass[found->s.number].second.emplace_back(
ETJump::stringFormat(R"(%s "%s")", key, value));
}

break;
default:
G_Printf(S_COLOR_YELLOW "%s: invalid key '%s'\n", __func__, key);
Expand Down
35 changes: 21 additions & 14 deletions src/game/g_spawn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* desc:
*
*/
#include "etj_entity_utilities.h"

#include <sstream>
#include <string>
#include <unordered_map>
Expand Down Expand Up @@ -172,6 +174,8 @@ field_t fields[] = {
{"targetShaderName", FOFS(targetShaderName), F_LSTRING},
{"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING},

{"cursorhint", FOFS(s.dmgFlags), F_CURSORHINT},

{nullptr}};

typedef struct {
Expand Down Expand Up @@ -808,42 +812,45 @@ in a gentity
===============
*/
void G_ParseField(const char *key, const char *value, gentity_t *ent) {
field_t *f;
byte *b;
float v;
vec3_t vec;

for (f = fields; f->name; f++) {
for (const field_t *f = fields; f->name; f++) {
if (!Q_stricmp(f->name, key)) {
// found it
b = (byte *)ent;
const auto b = reinterpret_cast<byte *>(ent);

switch (f->type) {
case F_LSTRING:
*(char **)(b + f->ofs) = G_NewString(value);
*reinterpret_cast<char **>(b + f->ofs) = G_NewString(value);
break;
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];
reinterpret_cast<float *>(b + f->ofs)[0] = vec[0];
reinterpret_cast<float *>(b + f->ofs)[1] = vec[1];
reinterpret_cast<float *>(b + f->ofs)[2] = vec[2];
break;
case F_INT:
*(int *)(b + f->ofs) = Q_atoi(value);
*reinterpret_cast<int *>(b + f->ofs) = Q_atoi(value);
break;
case F_FLOAT:
*(float *)(b + f->ofs) = Q_atof(value);
*reinterpret_cast<float *>(b + f->ofs) = Q_atof(value);
break;
case F_ANGLEHACK:
v = Q_atof(value);
((float *)(b + f->ofs))[0] = 0;
((float *)(b + f->ofs))[1] = v;
((float *)(b + f->ofs))[2] = 0;
reinterpret_cast<float *>(b + f->ofs)[0] = 0;
reinterpret_cast<float *>(b + f->ofs)[1] = v;
reinterpret_cast<float *>(b + f->ofs)[2] = 0;
break;
case F_CURSORHINT:
ETJump::EntityUtilities::setCursorhintFromString(
*reinterpret_cast<int *>(b + f->ofs), value);
break;
default:
case F_IGNORE:
default:
break;
}

return;
}
}
Expand Down

0 comments on commit 7a06fe2

Please sign in to comment.