Reworked configs to use a more elegant key->value format.
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
//
|
//
|
||||||
// botman's monster - MetaMOD plugin
|
// Monster Mod is a modification based on Botman's original "Monster" plugin.
|
||||||
|
// The "forgotten" modification was made by Rick90.
|
||||||
|
// This is an attempt to recreate the plugin so it does not become lost again.
|
||||||
|
//
|
||||||
|
// Recreated by Giegue.
|
||||||
//
|
//
|
||||||
// dllapi.cpp
|
// dllapi.cpp
|
||||||
//
|
//
|
||||||
@@ -101,20 +105,23 @@ DLL_DECALLIST gDecals[] = {
|
|||||||
|
|
||||||
monster_type_t monster_types[]=
|
monster_type_t monster_types[]=
|
||||||
{
|
{
|
||||||
"agrunt", FALSE,
|
// These are just names. But to keep it consistent
|
||||||
"apache", FALSE,
|
// with the new KVD format, ensure these are exactly
|
||||||
"barney", FALSE,
|
// like an actual, entity classname.
|
||||||
"bigmomma", FALSE,
|
"monster_alien_grunt", FALSE,
|
||||||
"bullsquid", FALSE,
|
"monster_apache", FALSE,
|
||||||
"controller", FALSE,
|
"monster_barney", FALSE,
|
||||||
"hassassin", FALSE,
|
"monster_bigmomma", FALSE,
|
||||||
"headcrab", FALSE,
|
"monster_bullsquid", FALSE,
|
||||||
"hgrunt", FALSE,
|
"monster_alien_controller", FALSE,
|
||||||
"houndeye", FALSE,
|
"monster_hassassin", FALSE,
|
||||||
"islave", FALSE,
|
"monster_headcrab", FALSE,
|
||||||
"scientist", FALSE,
|
"monster_human_grunt", FALSE,
|
||||||
"snark", FALSE,
|
"monster_houndeye", FALSE,
|
||||||
"zombie", FALSE,
|
"monster_alien_slave", FALSE,
|
||||||
|
"monster_scientist", FALSE,
|
||||||
|
"monster_snark", FALSE,
|
||||||
|
"monster_zombie", FALSE,
|
||||||
"", FALSE
|
"", FALSE
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -320,7 +327,7 @@ void check_monster_dead(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool spawn_monster(int monster_type, Vector origin, float angle, int respawn_index)
|
bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_index)
|
||||||
{
|
{
|
||||||
int monster_index;
|
int monster_index;
|
||||||
edict_t *monster_pent;
|
edict_t *monster_pent;
|
||||||
@@ -399,8 +406,12 @@ bool spawn_monster(int monster_type, Vector origin, float angle, int respawn_ind
|
|||||||
monsters[monster_index].monster_index = (*g_engfuncs.pfnIndexOfEdict)(monster_pent);
|
monsters[monster_index].monster_index = (*g_engfuncs.pfnIndexOfEdict)(monster_pent);
|
||||||
|
|
||||||
monster_pent->v.origin = origin;
|
monster_pent->v.origin = origin;
|
||||||
monster_pent->v.angles.y = angle;
|
monster_pent->v.angles = angles;
|
||||||
|
|
||||||
|
// Since the entity is now linked to the class above,
|
||||||
|
// it's pev->classname should be, theorically, safe to edit.
|
||||||
|
// The pev->classname is set in the monster's Spawn() function.
|
||||||
|
//monster_pent->v.classname = MAKE_STRING("monster_zombie");
|
||||||
monsters[monster_index].pMonster->Spawn();
|
monsters[monster_index].pMonster->Spawn();
|
||||||
|
|
||||||
monster_pent->v.spawnflags = SF_MONSTER_FADECORPSE;
|
monster_pent->v.spawnflags = SF_MONSTER_FADECORPSE;
|
||||||
@@ -412,10 +423,9 @@ bool spawn_monster(int monster_type, Vector origin, float angle, int respawn_ind
|
|||||||
|
|
||||||
void check_respawn(void)
|
void check_respawn(void)
|
||||||
{
|
{
|
||||||
int type_index;
|
|
||||||
int monster_type;
|
int monster_type;
|
||||||
Vector origin;
|
Vector origin;
|
||||||
float angle;
|
Vector angles;
|
||||||
|
|
||||||
if (!monster_spawn->value)
|
if (!monster_spawn->value)
|
||||||
return; // monster_spawn is turned off, retry again later
|
return; // monster_spawn is turned off, retry again later
|
||||||
@@ -427,20 +437,13 @@ void check_respawn(void)
|
|||||||
{
|
{
|
||||||
monster_spawnpoint[index].need_to_respawn = FALSE;
|
monster_spawnpoint[index].need_to_respawn = FALSE;
|
||||||
|
|
||||||
type_index = RANDOM_LONG(0, monster_spawnpoint[index].monster_count-1);
|
monster_type = monster_spawnpoint[index].monster;
|
||||||
|
|
||||||
monster_type = monster_spawnpoint[index].monster[type_index];
|
|
||||||
|
|
||||||
origin = monster_spawnpoint[index].origin;
|
origin = monster_spawnpoint[index].origin;
|
||||||
|
|
||||||
angle = monster_spawnpoint[index].angle_min;
|
angles = monster_spawnpoint[index].angles;
|
||||||
|
|
||||||
if (angle != monster_spawnpoint[index].angle_max)
|
if (spawn_monster(monster_type, origin, angles, index))
|
||||||
{
|
|
||||||
angle = RANDOM_FLOAT(angle, monster_spawnpoint[index].angle_max);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spawn_monster(monster_type, origin, angle, index))
|
|
||||||
{
|
{
|
||||||
// spawn_monster failed, retry again after delay...
|
// spawn_monster failed, retry again after delay...
|
||||||
monster_spawnpoint[index].need_to_respawn = TRUE;
|
monster_spawnpoint[index].need_to_respawn = TRUE;
|
||||||
@@ -573,7 +576,7 @@ void MonsterCommand(void)
|
|||||||
Vector origin = pPlayer->v.origin;
|
Vector origin = pPlayer->v.origin;
|
||||||
Vector view_angle = pPlayer->v.v_angle;
|
Vector view_angle = pPlayer->v.v_angle;
|
||||||
Vector v_src, v_dest;
|
Vector v_src, v_dest;
|
||||||
float monster_angle;
|
Vector monster_angle;
|
||||||
|
|
||||||
// try to determine the best place to spawn the monster...
|
// try to determine the best place to spawn the monster...
|
||||||
|
|
||||||
@@ -596,11 +599,11 @@ void MonsterCommand(void)
|
|||||||
|
|
||||||
if (tr.flFraction < 1.0) // hit something?
|
if (tr.flFraction < 1.0) // hit something?
|
||||||
{
|
{
|
||||||
monster_angle = view_angle.y + 180.0f; // face the player
|
monster_angle.y = view_angle.y + 180.0f; // face the player
|
||||||
if (monster_angle > 360)
|
if (monster_angle.y > 360)
|
||||||
monster_angle -= 360;
|
monster_angle.y -= 360;
|
||||||
if (monster_angle < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1);
|
spawn_monster(monster_type, v_src, monster_angle, -1);
|
||||||
|
|
||||||
@@ -624,11 +627,11 @@ void MonsterCommand(void)
|
|||||||
|
|
||||||
if (tr.flFraction < 1.0) // hit something?
|
if (tr.flFraction < 1.0) // hit something?
|
||||||
{
|
{
|
||||||
monster_angle = view_angle.y - 135.0f; // face the player
|
monster_angle.y = view_angle.y - 135.0f; // face the player
|
||||||
if (monster_angle > 360)
|
if (monster_angle.y > 360)
|
||||||
monster_angle -= 360;
|
monster_angle.y -= 360;
|
||||||
if (monster_angle < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1);
|
spawn_monster(monster_type, v_src, monster_angle, -1);
|
||||||
|
|
||||||
@@ -652,11 +655,11 @@ void MonsterCommand(void)
|
|||||||
|
|
||||||
if (tr.flFraction < 1.0) // hit something?
|
if (tr.flFraction < 1.0) // hit something?
|
||||||
{
|
{
|
||||||
monster_angle = view_angle.y + 135.0f; // face the player
|
monster_angle.y = view_angle.y + 135.0f; // face the player
|
||||||
if (monster_angle > 360)
|
if (monster_angle.y > 360)
|
||||||
monster_angle -= 360;
|
monster_angle.y -= 360;
|
||||||
if (monster_angle < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1);
|
spawn_monster(monster_type, v_src, monster_angle, -1);
|
||||||
|
|
||||||
@@ -679,11 +682,11 @@ void MonsterCommand(void)
|
|||||||
|
|
||||||
if (tr.flFraction < 1.0) // hit something?
|
if (tr.flFraction < 1.0) // hit something?
|
||||||
{
|
{
|
||||||
monster_angle = view_angle.y + 90.0f; // face the player
|
monster_angle.y = view_angle.y + 90.0f; // face the player
|
||||||
if (monster_angle > 360)
|
if (monster_angle.y > 360)
|
||||||
monster_angle -= 360;
|
monster_angle.y -= 360;
|
||||||
if (monster_angle < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1);
|
spawn_monster(monster_type, v_src, monster_angle, -1);
|
||||||
|
|
||||||
@@ -706,11 +709,11 @@ void MonsterCommand(void)
|
|||||||
|
|
||||||
if (tr.flFraction < 1.0) // hit something?
|
if (tr.flFraction < 1.0) // hit something?
|
||||||
{
|
{
|
||||||
monster_angle = view_angle.y - 90.0f; // face the player
|
monster_angle.y = view_angle.y - 90.0f; // face the player
|
||||||
if (monster_angle > 360)
|
if (monster_angle.y > 360)
|
||||||
monster_angle -= 360;
|
monster_angle.y -= 360;
|
||||||
if (monster_angle < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1);
|
spawn_monster(monster_type, v_src, monster_angle, -1);
|
||||||
|
|
||||||
@@ -733,11 +736,11 @@ void MonsterCommand(void)
|
|||||||
|
|
||||||
if (tr.flFraction < 1.0) // hit something?
|
if (tr.flFraction < 1.0) // hit something?
|
||||||
{
|
{
|
||||||
monster_angle = view_angle.y; // face the player
|
monster_angle.y = view_angle.y; // face the player
|
||||||
if (monster_angle > 360)
|
if (monster_angle.y > 360)
|
||||||
monster_angle -= 360;
|
monster_angle.y -= 360;
|
||||||
if (monster_angle < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1);
|
spawn_monster(monster_type, v_src, monster_angle, -1);
|
||||||
|
|
||||||
@@ -850,9 +853,14 @@ void mmDispatchThink( edict_t *pent )
|
|||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
|
// HACKHACK -- this is a hack to keep the node graph entity from "touching" things (like triggers)
|
||||||
|
// while it builds the graph
|
||||||
|
BOOL gTouchDisabled = FALSE;
|
||||||
void mmDispatchTouch( edict_t *pentTouched, edict_t *pentOther )
|
void mmDispatchTouch( edict_t *pentTouched, edict_t *pentOther )
|
||||||
{
|
{
|
||||||
|
if (gTouchDisabled)
|
||||||
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
|
|
||||||
for (int index=0; index < monster_ents_used; index++)
|
for (int index=0; index < monster_ents_used; index++)
|
||||||
{
|
{
|
||||||
if ((pentTouched != NULL) && (pentTouched == monsters[index].monster_pent))
|
if ((pentTouched != NULL) && (pentTouched == monsters[index].monster_pent))
|
||||||
|
|||||||
@@ -22,397 +22,305 @@ extern int monster_spawn_count;
|
|||||||
|
|
||||||
bool get_input(FILE *fp, char *input)
|
bool get_input(FILE *fp, char *input)
|
||||||
{
|
{
|
||||||
char line[1024];
|
char line[1024];
|
||||||
int len, pos;
|
int len, pos;
|
||||||
|
|
||||||
while (!feof(fp))
|
while (!feof(fp))
|
||||||
{
|
{
|
||||||
if (fgets(line, 1023, fp) != NULL)
|
if (fgets(line, 1023, fp) != NULL)
|
||||||
{
|
{
|
||||||
len = strlen(line);
|
len = strlen(line);
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
continue; // skip any null lines
|
continue; // skip any null lines
|
||||||
|
|
||||||
// remove any trailing newline, carriage return or whitespace...
|
// remove any trailing newline, carriage return or whitespace...
|
||||||
while ((line[len-1] == '\n') || (line[len-1] == '\r') ||
|
while ((line[len-1] == '\n') || (line[len-1] == '\r') || isspace(line[len-1]))
|
||||||
isspace(line[len-1]))
|
{
|
||||||
{
|
line[len-1] = 0;
|
||||||
line[len-1] = 0;
|
len--;
|
||||||
len--;
|
if (len == 0)
|
||||||
if (len == 0)
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
|
|
||||||
while (isspace(line[pos]))
|
while (isspace(line[pos]))
|
||||||
pos++; // skip leading blanks
|
pos++; // skip leading blanks
|
||||||
|
|
||||||
if ((line[pos] == '/') && (line[pos+1] == '/'))
|
if ((line[pos] == '/') && (line[pos+1] == '/'))
|
||||||
continue; // skip comment lines
|
continue; // skip comment lines
|
||||||
|
|
||||||
if (line[pos] == 0)
|
if (line[pos] == 0)
|
||||||
continue; // skip empty lines
|
continue; // skip empty lines
|
||||||
|
|
||||||
strcpy(input, &line[pos]);
|
strcpy(input, &line[pos]);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE; // no input found
|
return FALSE; // no input found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct pKVD
|
||||||
bool scan_monster_cfg(FILE *fp)
|
|
||||||
{
|
{
|
||||||
char input[1024];
|
char key[33];
|
||||||
bool origin, angle, delay, angle_min, angle_max, monster;
|
char value[33];
|
||||||
float x, y, z;
|
};
|
||||||
|
void scan_monster_cfg(FILE *fp)
|
||||||
|
{
|
||||||
|
// Let's make a full rework of this. -Giegue
|
||||||
|
char input[1024];
|
||||||
|
float x, y, z;
|
||||||
|
|
||||||
while (get_input(fp, input))
|
while (get_input(fp, input))
|
||||||
{
|
{
|
||||||
if (monster_spawn_count == MAX_MONSTERS)
|
if (input[0] == '{')
|
||||||
continue; // skip if max monster spawn count reached
|
{
|
||||||
|
// Proper start, initialize entity creation
|
||||||
|
// Temporary variables to store entity data
|
||||||
|
pKVD *data = (pKVD*)malloc(32*sizeof(*data)); // Entities should not have more than 32 keyvalues
|
||||||
|
int kvd_index = 0;
|
||||||
|
while (get_input(fp, input))
|
||||||
|
{
|
||||||
|
// It's the end of the entity structure?
|
||||||
|
if (input[0] == '}')
|
||||||
|
{
|
||||||
|
// Done. Let's process the keyvalues.
|
||||||
|
for (int i = 0; i < kvd_index; i++)
|
||||||
|
{
|
||||||
|
float x, y, z;
|
||||||
|
// Any unknown keyvalue is ignored.
|
||||||
|
// Any duplicate keyvalue is overwritten.
|
||||||
|
|
||||||
if (input[0] == '{')
|
if (strcmp(data[i].key, "origin") == 0)
|
||||||
{
|
{
|
||||||
origin = angle = delay = angle_min = angle_max = monster = FALSE;
|
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: invalid origin: %s", input); // print conflictive line
|
||||||
|
|
||||||
monster_spawnpoint[monster_spawn_count].monster_count = 0;
|
// reset origin to g_vecZero
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: entity will spawn at 0 0 0");
|
||||||
|
x = y = z = 0;
|
||||||
|
}
|
||||||
|
monster_spawnpoint[monster_spawn_count].origin[0] = x;
|
||||||
|
monster_spawnpoint[monster_spawn_count].origin[1] = y;
|
||||||
|
monster_spawnpoint[monster_spawn_count].origin[2] = z;
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "delay") == 0)
|
||||||
|
{
|
||||||
|
// ToDo: Remove this keyvalue.
|
||||||
|
// Monsters spawned directly should not respawn.
|
||||||
|
if (sscanf(data[i].value, "%f", &x) != 1)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: invalid delay: %s", input); // print conflictive line
|
||||||
|
|
||||||
while (get_input(fp, input))
|
// default to 30 seconds
|
||||||
{
|
LOG_MESSAGE(PLID, "ERROR: entity respawn frequency will be set to 30 seconds");
|
||||||
if (input[0] == '}')
|
x = 30;
|
||||||
break;
|
}
|
||||||
|
monster_spawnpoint[monster_spawn_count].delay = x;
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "angles") == 0)
|
||||||
|
{
|
||||||
|
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: invalid angles: %s", input); // print conflictive line
|
||||||
|
|
||||||
if (strncmp(input, "origin/", 7) == 0)
|
// reset angles to g_vecZero
|
||||||
{
|
LOG_MESSAGE(PLID, "ERROR: entity angles will be set to 0 0 0");
|
||||||
if (origin)
|
x = y = z = 0;
|
||||||
{
|
}
|
||||||
//META_CONS("[MONSTER] ERROR: origin found twice: %s", input);
|
monster_spawnpoint[monster_spawn_count].angles[0] = x;
|
||||||
LOG_MESSAGE(PLID, "ERROR: origin found twice: %s", input);
|
monster_spawnpoint[monster_spawn_count].angles[1] = y;
|
||||||
return TRUE; // error
|
monster_spawnpoint[monster_spawn_count].angles[2] = z;
|
||||||
}
|
}
|
||||||
if (sscanf(&input[7], "%f %f %f", &x, &y, &z) != 3)
|
else if (strcmp(data[i].key, "classname") == 0)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: invalid origin: %s", input);
|
int mIndex;
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid origin: %s", input);
|
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
|
||||||
return TRUE; // error
|
{
|
||||||
}
|
if (strcmp(data[i].value, monster_types[mIndex].name) == 0)
|
||||||
origin = TRUE;
|
{
|
||||||
monster_spawnpoint[monster_spawn_count].origin[0] = x;
|
monster_spawnpoint[monster_spawn_count].monster = mIndex;
|
||||||
monster_spawnpoint[monster_spawn_count].origin[1] = y;
|
monster_types[mIndex].need_to_precache = TRUE;
|
||||||
monster_spawnpoint[monster_spawn_count].origin[2] = z;
|
break;
|
||||||
}
|
}
|
||||||
else if (strncmp(input, "delay/", 6) == 0)
|
}
|
||||||
{
|
if (monster_types[mIndex].name[0] == 0)
|
||||||
if (delay)
|
{
|
||||||
{
|
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", input); // print conflictive line
|
||||||
//META_CONS("[MONSTER] ERROR: delay found twice: %s", input);
|
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
||||||
LOG_MESSAGE(PLID, "ERROR: delay found twice: %s", input);
|
}
|
||||||
return TRUE; // error
|
}
|
||||||
}
|
}
|
||||||
if (sscanf(&input[6], "%f", &x) != 1)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: invalid delay: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid delay: %s", input);
|
|
||||||
return TRUE; // error
|
|
||||||
}
|
|
||||||
delay = TRUE;
|
|
||||||
monster_spawnpoint[monster_spawn_count].delay = x;
|
|
||||||
}
|
|
||||||
else if (strncmp(input, "angle/", 6) == 0)
|
|
||||||
{
|
|
||||||
if (angle)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: angle found twice: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: angle found twice: %s", input);
|
|
||||||
return TRUE; // error
|
|
||||||
}
|
|
||||||
if (angle_min || angle_max)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: you can't specify angle AND angle_min or angle_max: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: you can't specify angle AND angle_min or angle_max: %s", input);
|
|
||||||
return TRUE; // error
|
|
||||||
}
|
|
||||||
if (sscanf(&input[6], "%f", &x) != 1)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: invalid angle: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid angle: %s", input);
|
|
||||||
return TRUE; // error
|
|
||||||
}
|
|
||||||
angle = TRUE;
|
|
||||||
monster_spawnpoint[monster_spawn_count].angle_min = x;
|
|
||||||
monster_spawnpoint[monster_spawn_count].angle_max = x;
|
|
||||||
}
|
|
||||||
else if (strncmp(input, "angle_min/", 10) == 0)
|
|
||||||
{
|
|
||||||
if (angle_min)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: angle_min found twice: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: angle_min found twice: %s", input);
|
|
||||||
return TRUE; // error
|
|
||||||
}
|
|
||||||
if (angle)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: you can't specify angle AND angle_min or angle_max: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: you can't specify angle AND angle_min or angle_max: %s", input);
|
|
||||||
return TRUE; // error
|
|
||||||
}
|
|
||||||
if (sscanf(&input[10], "%f", &x) != 1)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: invalid angle_min: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid angle_min: %s", input);
|
|
||||||
return TRUE; // error
|
|
||||||
}
|
|
||||||
angle_min = TRUE;
|
|
||||||
monster_spawnpoint[monster_spawn_count].angle_min = x;
|
|
||||||
}
|
|
||||||
else if (strncmp(input, "angle_max/", 10) == 0)
|
|
||||||
{
|
|
||||||
if (angle_max)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: angle_max found twice: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: angle_max found twice: %s", input);
|
|
||||||
return TRUE; // error
|
|
||||||
}
|
|
||||||
if (angle)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: you can't specify angle AND angle_min or angle_max: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: you can't specify angle AND angle_min or angle_max: %s", input);
|
|
||||||
return TRUE; // error
|
|
||||||
}
|
|
||||||
if (sscanf(&input[10], "%f", &x) != 1)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: invalid angle_max: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid angle_max: %s", input);
|
|
||||||
return TRUE; // error
|
|
||||||
}
|
|
||||||
angle_max = TRUE;
|
|
||||||
monster_spawnpoint[monster_spawn_count].angle_max = x;
|
|
||||||
}
|
|
||||||
else if (strncmp(input, "monster/", 8) == 0)
|
|
||||||
{
|
|
||||||
int index;
|
|
||||||
int count = monster_spawnpoint[monster_spawn_count].monster_count;
|
|
||||||
if (count < MAX_MONSTER_COUNT)
|
|
||||||
{
|
|
||||||
for (index=0; monster_types[index].name[0]; index++)
|
|
||||||
{
|
|
||||||
if (strcmp(&input[8], monster_types[index].name) == 0)
|
|
||||||
{
|
|
||||||
monster_spawnpoint[monster_spawn_count].monster[count] = index;
|
|
||||||
monster_spawnpoint[monster_spawn_count].monster_count++;
|
|
||||||
|
|
||||||
monster_types[index].need_to_precache = TRUE;
|
// Init monster
|
||||||
break;
|
monster_spawnpoint[monster_spawn_count].respawn_time = gpGlobals->time + 0.1; // spawn (nearly) right away
|
||||||
}
|
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
|
||||||
}
|
|
||||||
if (monster_types[index].name[0] == 0)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: invalid monster name: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid monster name: %s", input);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
monster = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: unknown command: %s", input);
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: unknown command: %s", input);
|
|
||||||
return TRUE; // error occurred
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for all necessary fields here...
|
// Log on? Print all the entities that were added
|
||||||
if (!origin)
|
if (dllapi_log->value)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: you didn't specify an origin!");
|
// Classname only, or we will flood the server!
|
||||||
LOG_MESSAGE(PLID, "ERROR: you didn't specify an origin!");
|
// No, I'm not making this idiotproof. Classname should be the last KVD entry on an entity!
|
||||||
return TRUE;
|
LOG_CONSOLE(PLID, "[DEBUG] Added entity: %s", data[kvd_index-1].value);
|
||||||
}
|
}
|
||||||
if (angle_min && !angle_max)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: you specified angle_min but didn't specify angle_max!");
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: you specified angle_min but didn't specify angle_max!");
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
if (angle_max && !angle_min)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: you specified angle_max but didn't specify angle_min!");
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: you specified angle_max but didn't specify angle_min!");
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
if (!monster)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: No monster key found!");
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: No monster key found!");
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!delay)
|
monster_spawn_count++;
|
||||||
monster_spawnpoint[monster_spawn_count].delay = 30; // 30 second default delay
|
free( data );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (monster_spawnpoint[monster_spawn_count].delay < 1)
|
// Bruteforce to remove quotes
|
||||||
monster_spawnpoint[monster_spawn_count].delay = 1; // no negative or zero delay
|
char parse[66] = {0};
|
||||||
|
int skip = 0;
|
||||||
|
for (int i = 0; i < strlen(input); i++)
|
||||||
|
{
|
||||||
|
if (input[i] == '"')
|
||||||
|
{
|
||||||
|
skip++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
parse[i-skip] = input[i];
|
||||||
|
}
|
||||||
|
parse[strlen(parse)] = '\0';
|
||||||
|
|
||||||
if (!angle && !angle_min && !angle_max) // no angle specified, use 0-359 as default
|
// Copy all keyvalues to the tempvar
|
||||||
{
|
// Key
|
||||||
monster_spawnpoint[monster_spawn_count].angle_min = 0;
|
char *copy = strtok(parse, " ");
|
||||||
monster_spawnpoint[monster_spawn_count].angle_max = 359;
|
strcpy(data[kvd_index].key, copy);
|
||||||
}
|
|
||||||
|
|
||||||
if (monster_spawnpoint[monster_spawn_count].angle_min < 0)
|
// Value
|
||||||
monster_spawnpoint[monster_spawn_count].angle_min = 0; // no negative angles
|
copy = strtok(NULL, " ");
|
||||||
|
strcpy(data[kvd_index].value, "");
|
||||||
|
while (copy != NULL)
|
||||||
|
{
|
||||||
|
// If the value is a vector, append necessary whitespaces
|
||||||
|
strcat(data[kvd_index].value, copy);
|
||||||
|
copy = strtok(NULL, " ");
|
||||||
|
if (copy != NULL)
|
||||||
|
strcat(data[kvd_index].value, " ");
|
||||||
|
}
|
||||||
|
|
||||||
if (monster_spawnpoint[monster_spawn_count].angle_max > 359)
|
// Next KVD
|
||||||
monster_spawnpoint[monster_spawn_count].angle_max = 359; // no angle > 359 degrees
|
kvd_index++;
|
||||||
|
}
|
||||||
monster_spawnpoint[monster_spawn_count].respawn_time = gpGlobals->time + RANDOM_FLOAT(10.0, 20.0);
|
}
|
||||||
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
|
}
|
||||||
|
|
||||||
if (dllapi_log->value)
|
|
||||||
{
|
|
||||||
char name_monsters[256];
|
|
||||||
|
|
||||||
LOG_MESSAGE(PLID, "Added monster spawn at: %7.2f %7.2f %7.2f",
|
|
||||||
monster_spawnpoint[monster_spawn_count].origin.x,
|
|
||||||
monster_spawnpoint[monster_spawn_count].origin.y,
|
|
||||||
monster_spawnpoint[monster_spawn_count].origin.z);
|
|
||||||
LOG_MESSAGE(PLID, " with delay = %7.2f, angle_min = %7.2f, angle_max = %7.2f",
|
|
||||||
monster_spawnpoint[monster_spawn_count].delay,
|
|
||||||
monster_spawnpoint[monster_spawn_count].angle_min,
|
|
||||||
monster_spawnpoint[monster_spawn_count].angle_max);
|
|
||||||
name_monsters[0] = 0;
|
|
||||||
for (int i = 0; i < monster_spawnpoint[monster_spawn_count].monster_count; i++)
|
|
||||||
{
|
|
||||||
strcat(name_monsters, monster_types[monster_spawnpoint[monster_spawn_count].monster[i]].name);
|
|
||||||
strcat(name_monsters, " ");
|
|
||||||
}
|
|
||||||
LOG_MESSAGE(PLID, " monsters = %s", name_monsters);
|
|
||||||
}
|
|
||||||
|
|
||||||
monster_spawn_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void process_monster_cfg(void)
|
||||||
bool process_monster_cfg(void)
|
|
||||||
{
|
{
|
||||||
char game_dir[256];
|
char game_dir[256];
|
||||||
char filename[256];
|
char filename[256];
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
bool status = FALSE; // no error
|
bool status = FALSE; // no error
|
||||||
|
|
||||||
monster_spawn_count = 0;
|
monster_spawn_count = 0;
|
||||||
|
|
||||||
// find the directory name of the currently running MOD...
|
// find the directory name of the currently running MOD...
|
||||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||||
|
|
||||||
strcpy(filename, game_dir);
|
strcpy(filename, game_dir);
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
strcat(filename, "/maps/");
|
strcat(filename, "/maps/");
|
||||||
#else
|
#else
|
||||||
strcat(filename, "\\maps\\");
|
strcat(filename, "\\maps\\");
|
||||||
#endif
|
#endif
|
||||||
strcat(filename, STRING(gpGlobals->mapname));
|
strcat(filename, STRING(gpGlobals->mapname));
|
||||||
strcat(filename, "_monster.cfg");
|
strcat(filename, "_monster.cfg");
|
||||||
|
|
||||||
// check if the map specific filename exists...
|
// check if the map specific filename exists...
|
||||||
if (access(filename, 0) == 0)
|
if (access(filename, 0) == 0)
|
||||||
{
|
{
|
||||||
if (dllapi_log->value)
|
if (dllapi_log->value)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] Processing config file=%s", filename);
|
//META_CONS("[MONSTER] Processing config file=%s", filename);
|
||||||
LOG_MESSAGE(PLID, "Processing config file=%s", filename);
|
LOG_MESSAGE(PLID, "Processing config file=%s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fp = fopen(filename, "r")) == NULL)
|
if ((fp = fopen(filename, "r")) == NULL)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
||||||
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename);
|
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename);
|
||||||
|
|
||||||
return TRUE; // return bad status
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = scan_monster_cfg(fp);
|
scan_monster_cfg(fp);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool scan_monster_precache_cfg(FILE *fp)
|
bool scan_monster_precache_cfg(FILE *fp)
|
||||||
{
|
{
|
||||||
char input[1024];
|
char input[1024];
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
while (get_input(fp, input))
|
while (get_input(fp, input))
|
||||||
{
|
{
|
||||||
found = FALSE;
|
found = FALSE;
|
||||||
|
|
||||||
for (int index=0; monster_types[index].name[0]; index++)
|
for (int index=0; monster_types[index].name[0]; index++)
|
||||||
{
|
{
|
||||||
if (strcmp(input, monster_types[index].name) == 0)
|
if (strcmp(input, monster_types[index].name) == 0)
|
||||||
{
|
{
|
||||||
monster_types[index].need_to_precache = TRUE;
|
monster_types[index].need_to_precache = TRUE;
|
||||||
found = TRUE;
|
found = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found == FALSE)
|
if (found == FALSE)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: invalid precache monster name: %s", input);
|
//META_CONS("[MONSTER] ERROR: invalid precache monster name: %s", input);
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid precache monster name: %s", input);
|
LOG_MESSAGE(PLID, "ERROR: invalid precache monster name: %s", input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool process_monster_precache_cfg(void)
|
bool process_monster_precache_cfg(void)
|
||||||
{
|
{
|
||||||
char game_dir[256];
|
char game_dir[256];
|
||||||
char filename[256];
|
char filename[256];
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
bool status = FALSE; // no error
|
bool status = FALSE; // no error
|
||||||
|
|
||||||
// find the directory name of the currently running MOD...
|
// find the directory name of the currently running MOD...
|
||||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||||
|
|
||||||
strcpy(filename, game_dir);
|
strcpy(filename, game_dir);
|
||||||
strcat(filename, "/monster_precache.cfg");
|
strcat(filename, "/monster_precache.cfg");
|
||||||
|
|
||||||
// check if the map specific filename exists...
|
// check if the map specific filename exists...
|
||||||
if (access(filename, 0) == 0)
|
if (access(filename, 0) == 0)
|
||||||
{
|
{
|
||||||
if (dllapi_log->value)
|
if (dllapi_log->value)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] Processing config file=%s", filename);
|
//META_CONS("[MONSTER] Processing config file=%s", filename);
|
||||||
LOG_MESSAGE(PLID, "Processing config file=%s", filename);
|
LOG_MESSAGE(PLID, "Processing config file=%s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fp = fopen(filename, "r")) == NULL)
|
if ((fp = fopen(filename, "r")) == NULL)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
||||||
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename);
|
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename);
|
||||||
|
|
||||||
return TRUE; // return bad status
|
return TRUE; // return bad status
|
||||||
}
|
}
|
||||||
|
|
||||||
status = scan_monster_precache_cfg(fp);
|
status = scan_monster_precache_cfg(fp);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,15 +28,11 @@ typedef struct
|
|||||||
|
|
||||||
extern monster_t monsters[MAX_MONSTER_ENTS];
|
extern monster_t monsters[MAX_MONSTER_ENTS];
|
||||||
|
|
||||||
|
|
||||||
#define MAX_MONSTER_COUNT 20
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Vector origin;
|
Vector origin;
|
||||||
float angle_min, angle_max;
|
Vector angles;
|
||||||
float delay;
|
float delay;
|
||||||
unsigned char monster[MAX_MONSTER_COUNT];
|
unsigned char monster;
|
||||||
int monster_count;
|
|
||||||
float respawn_time;
|
float respawn_time;
|
||||||
bool need_to_respawn;
|
bool need_to_respawn;
|
||||||
} monster_spawnpoint_t;
|
} monster_spawnpoint_t;
|
||||||
|
|||||||
Reference in New Issue
Block a user