mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-06 16:43:21 +00:00
Support editing lump
This commit is contained in:
parent
7f333fed70
commit
07360e59e3
1 changed files with 546 additions and 93 deletions
|
@ -5,6 +5,7 @@
|
|||
|
||||
#define PLUGIN_VERSION "1.0"
|
||||
#define DEBUG_SCENE_PARSE 1
|
||||
#define DEBUG_BLOCKERS 1
|
||||
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
|
@ -12,9 +13,20 @@
|
|||
#include <profiler>
|
||||
#include <json>
|
||||
#include <jutils>
|
||||
#include <entitylump>
|
||||
|
||||
int g_iLaserIndex;
|
||||
#if defined DEBUG_BLOCKERS
|
||||
#include <smlib/effects>
|
||||
#endif
|
||||
#define ENT_PROP_NAME "l4d2_randomizer"
|
||||
#define ENT_ENV_NAME "l4d2_randomizer"
|
||||
#define ENT_BLOCKER_NAME "l4d2_randomizer"
|
||||
#include <gamemodes/ents>
|
||||
|
||||
#define MAX_SCENE_NAME_LENGTH 32
|
||||
#define MAX_INPUTS_CLASSNAME_LENGTH 64
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "L4D2 Randomizer",
|
||||
|
@ -25,6 +37,11 @@ public Plugin myinfo =
|
|||
};
|
||||
|
||||
ConVar cvarEnabled;
|
||||
enum struct ActiveSceneData {
|
||||
char name[MAX_SCENE_NAME_LENGTH];
|
||||
int variantIndex;
|
||||
}
|
||||
MapData g_MapData;
|
||||
|
||||
public void OnPluginStart() {
|
||||
EngineVersion g_Game = GetEngineVersion();
|
||||
|
@ -35,15 +52,53 @@ public void OnPluginStart() {
|
|||
RegAdminCmd("sm_rcycle", Command_CycleRandom, ADMFLAG_CHEATS);
|
||||
RegAdminCmd("sm_expent", Command_ExportEnt, ADMFLAG_GENERIC);
|
||||
|
||||
HookEvent("round_start", Event_RoundStart);
|
||||
|
||||
cvarEnabled = CreateConVar("sm_randomizer_enabled", "0");
|
||||
|
||||
g_MapData.activeScenes = new ArrayList(sizeof(ActiveSceneData));
|
||||
}
|
||||
|
||||
char currentMap[64];
|
||||
|
||||
// TODO: on round start
|
||||
public void OnMapStart() {
|
||||
g_iLaserIndex = PrecacheModel("materials/sprites/laserbeam.vmt", true);
|
||||
GetCurrentMap(currentMap, sizeof(currentMap));
|
||||
}
|
||||
|
||||
public void OnMapInit(const char[] map) {
|
||||
if(cvarEnabled.BoolValue) {
|
||||
if(LoadMapData(currentMap, FLAG_NONE) && g_MapData.lumpEdits.Length > 0) {
|
||||
Log("Found %d lump edits, running...", g_MapData.lumpEdits.Length);
|
||||
LumpEditData lump;
|
||||
for(int i = 0; i < g_MapData.lumpEdits.Length; i++) {
|
||||
g_MapData.lumpEdits.GetArray(i, lump);
|
||||
lump.Trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) {
|
||||
if(cvarEnabled.BoolValue) {
|
||||
CreateTimer(10.0, Timer_LoadMap);
|
||||
}
|
||||
}
|
||||
|
||||
Action Timer_LoadMap(Handle h) {
|
||||
if(cvarEnabled.BoolValue) {
|
||||
RunMap(currentMap, FLAG_NONE);
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public void OnMapEnd() {
|
||||
DeleteCustomEnts();
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
int GetLookingEntity(int client, TraceEntityFilter filter) {
|
||||
static float pos[3], ang[3];
|
||||
stock int GetLookingEntity(int client, TraceEntityFilter filter) {
|
||||
float pos[3], ang[3];
|
||||
GetClientEyePosition(client, pos);
|
||||
GetClientEyeAngles(client, ang);
|
||||
TR_TraceRayFilter(pos, ang, MASK_SOLID, RayType_Infinite, filter, client);
|
||||
|
@ -53,57 +108,96 @@ int GetLookingEntity(int client, TraceEntityFilter filter) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
stock int GetLookingPosition(int client, TraceEntityFilter filter, float pos[3]) {
|
||||
float ang[3];
|
||||
GetClientEyePosition(client, pos);
|
||||
GetClientEyeAngles(client, ang);
|
||||
TR_TraceRayFilter(pos, ang, MASK_SOLID, RayType_Infinite, filter, client);
|
||||
if(TR_DidHit()) {
|
||||
TR_GetEndPosition(pos);
|
||||
return TR_GetEntityIndex();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
public Action Command_CycleRandom(int client, int args) {
|
||||
DeleteCustomEnts();
|
||||
char map[64];
|
||||
GetCurrentMap(map, sizeof(map));
|
||||
LoadMap(map);
|
||||
ReplyToCommand(client, "Done.");
|
||||
if(args > 0) {
|
||||
DeleteCustomEnts();
|
||||
|
||||
char arg1[8];
|
||||
GetCmdArg(1, arg1, sizeof(arg1));
|
||||
int flags = StringToInt(arg1) | view_as<int>(FLAG_REFRESH);
|
||||
RunMap(currentMap, flags);
|
||||
if(client > 0)
|
||||
PrintCenterText(client, "Cycled flags=%d", flags);
|
||||
} else {
|
||||
ReplyToCommand(client, "Active Scenes:");
|
||||
ActiveSceneData scene;
|
||||
for(int i = 0; i < g_MapData.activeScenes.Length; i++) {
|
||||
g_MapData.activeScenes.GetArray(i, scene);
|
||||
ReplyToCommand(client, "\t%s: variant #%d", scene.name, scene.variantIndex);
|
||||
}
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action Command_ExportEnt(int client, int args) {
|
||||
int entity = GetLookingEntity(client, Filter_IgnorePlayer);
|
||||
float origin[3];
|
||||
int entity = GetLookingPosition(client, Filter_IgnorePlayer, origin);
|
||||
float angles[3];
|
||||
float size[3];
|
||||
char arg1[32];
|
||||
GetCmdArg(1, arg1, sizeof(arg1));
|
||||
if(entity > 0) {
|
||||
float origin[3];
|
||||
float angles[3];
|
||||
float size[3];
|
||||
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", origin);
|
||||
GetEntPropVector(entity, Prop_Send, "m_angRotation", angles);
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", size);
|
||||
|
||||
char model[64];
|
||||
GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||
|
||||
ReplyToCommand(client, "{");
|
||||
ReplyToCommand(client, "\t\"model\": \"%s\",", model);
|
||||
GetEntityClassname(entity, model, sizeof(model));
|
||||
if(StrContains(model, "prop_") == -1) {
|
||||
ReplyToCommand(client, "\t\"scale\": [%.2f, %.2f, %.2f],", size[0], size[1], size[2]);
|
||||
}
|
||||
if(StrEqual(arg1, "hammerid")) {
|
||||
int hammerid = GetEntProp(entity, Prop_Data, "m_iHammerID");
|
||||
ReplyToCommand(client, "\t\"type\": \"hammerid\",");
|
||||
ReplyToCommand(client, "\t\"model\": \"%d\",", hammerid);
|
||||
} else if(StrEqual(arg1, "targetname")) {
|
||||
GetEntPropString(entity, Prop_Data, "m_iName", model, sizeof(model));
|
||||
ReplyToCommand(client, "\t\"type\": \"targetname\",");
|
||||
ReplyToCommand(client, "\t\"model\": \"%s\",", model);
|
||||
} else {
|
||||
GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||
ReplyToCommand(client, "\t\"model\": \"%s\",", model);
|
||||
}
|
||||
ReplyToCommand(client, "\t\"origin\": [%.2f, %.2f, %.2f],", origin[0], origin[1], origin[2]);
|
||||
ReplyToCommand(client, "\t\"angles\": [%.2f, %.2f, %.2f],", angles[0], angles[1], angles[2]);
|
||||
ReplyToCommand(client, "\t\"size\": [%.2f, %.2f, %.2f]", size[0], size[1], size[2]);
|
||||
ReplyToCommand(client, "\t\"angles\": [%.2f, %.2f, %.2f]", angles[0], angles[1], angles[2]);
|
||||
ReplyToCommand(client, "}");
|
||||
} else {
|
||||
PrintCenterText(client, "No entity found");
|
||||
if(!StrEqual(arg1, "cursor"))
|
||||
GetEntPropVector(client, Prop_Send, "m_vecOrigin", origin);
|
||||
GetEntPropVector(client, Prop_Send, "m_angRotation", angles);
|
||||
ReplyToCommand(client, "{");
|
||||
ReplyToCommand(client, "\t\"type\": \"%s\",", arg1);
|
||||
ReplyToCommand(client, "\t\"scale\": [%.2f, %.2f, %.2f],", size[0], size[1], size[2]);
|
||||
ReplyToCommand(client, "\t\"origin\": [%.2f, %.2f, %.2f],", origin[0], origin[1], origin[2]);
|
||||
ReplyToCommand(client, "\t\"angles\": [%.2f, %.2f, %.2f]", angles[0], angles[1], angles[2]);
|
||||
ReplyToCommand(client, "}");
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public void OnMapStart() {
|
||||
if(cvarEnabled.BoolValue) {
|
||||
char map[64];
|
||||
GetCurrentMap(map, sizeof(map));
|
||||
LoadMap(map);
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_SCENE_NAME_LENGTH 32
|
||||
enum struct SceneData {
|
||||
char name[MAX_SCENE_NAME_LENGTH];
|
||||
float chance;
|
||||
ArrayList exclusions;
|
||||
char group[MAX_SCENE_NAME_LENGTH];
|
||||
ArrayList variants;
|
||||
|
||||
void Cleanup() {
|
||||
delete this.exclusions;
|
||||
SceneVariantData choice;
|
||||
for(int i = 0; i < this.variants.Length; i++) {
|
||||
this.variants.GetArray(i, choice);
|
||||
|
@ -115,26 +209,178 @@ enum struct SceneData {
|
|||
|
||||
enum struct SceneVariantData {
|
||||
int weight;
|
||||
ArrayList inputsList;
|
||||
ArrayList entities;
|
||||
|
||||
void Cleanup() {
|
||||
delete this.inputsList;
|
||||
delete this.entities;
|
||||
}
|
||||
}
|
||||
|
||||
enum struct VariantEntityData {
|
||||
char type[16];
|
||||
char type[32];
|
||||
char model[64];
|
||||
float origin[3];
|
||||
float angles[3];
|
||||
float scale[3];
|
||||
int color[4];
|
||||
}
|
||||
|
||||
ArrayList scenes;
|
||||
enum InputType {
|
||||
Input_Classname,
|
||||
Input_Targetname,
|
||||
Input_HammerId
|
||||
}
|
||||
enum struct VariantInputData {
|
||||
char name[MAX_INPUTS_CLASSNAME_LENGTH];
|
||||
InputType type;
|
||||
char input[32];
|
||||
|
||||
// Parses (mapname).json and runs chances
|
||||
public bool LoadMap(const char[] map) {
|
||||
void Trigger() {
|
||||
int entity = -1;
|
||||
switch(this.type) {
|
||||
case Input_Classname: {
|
||||
entity = FindEntityByClassname(entity, this.name);
|
||||
this._trigger(entity);
|
||||
}
|
||||
case Input_Targetname: {
|
||||
char targetname[32];
|
||||
while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE) {
|
||||
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
||||
if(StrEqual(targetname, this.name)) {
|
||||
this._trigger(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
case Input_HammerId: {
|
||||
int targetId = StringToInt(this.name);
|
||||
while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE) {
|
||||
int hammerId = GetEntProp(entity, Prop_Data, "m_iHammerID");
|
||||
if(hammerId == targetId ) {
|
||||
this._trigger(entity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _trigger(int entity) {
|
||||
if(entity > 0 && IsValidEntity(entity)) {
|
||||
if(StrEqual(this.input, "_allow_ladder")) {
|
||||
if(HasEntProp(entity, Prop_Send, "m_iTeamNum")) {
|
||||
SetEntProp(entity, Prop_Send, "m_iTeamNum", 0);
|
||||
} else {
|
||||
Log("Warn: Entity (%d) with id \"%s\" has no teamnum for \"_allow_ladder\"", entity, this.name);
|
||||
}
|
||||
} else if(StrEqual(this.input, "_lock")) {
|
||||
AcceptEntityInput(entity, "Close");
|
||||
AcceptEntityInput(entity, "Lock");
|
||||
} else if(StrEqual(this.input, "_lock_nobreak")) {
|
||||
AcceptEntityInput(entity, "Close");
|
||||
AcceptEntityInput(entity, "Lock");
|
||||
AcceptEntityInput(entity, "SetUnbreakable");
|
||||
}else {
|
||||
char cmd[32];
|
||||
// Split input "a b" to a with variant "b"
|
||||
int len = SplitString(this.input, " ", cmd, sizeof(cmd));
|
||||
if(len > -1) SetVariantString(this.input[len]);
|
||||
|
||||
Debug("_trigger(%d): %s (v=%s)", entity, this.input, cmd);
|
||||
AcceptEntityInput(entity, this.input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum struct LumpEditData {
|
||||
char name[MAX_INPUTS_CLASSNAME_LENGTH];
|
||||
InputType type;
|
||||
char action[32];
|
||||
char value[64];
|
||||
|
||||
int _findLumpIndex(int startIndex = 0, EntityLumpEntry entry) {
|
||||
int length = EntityLump.Length();
|
||||
char val[64];
|
||||
Debug("Scanning for \"%s\" (type=%d)", this.name, this.type);
|
||||
for(int i = startIndex; i < length; i++) {
|
||||
entry = EntityLump.Get(i);
|
||||
int index = entry.FindKey("hammerid");
|
||||
if(index != -1) {
|
||||
entry.Get(index, "", 0, val, sizeof(val));
|
||||
if(StrEqual(val, this.name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
index = entry.FindKey("classname");
|
||||
if(index != -1) {
|
||||
entry.Get(index, "", 0, val, sizeof(val));
|
||||
Debug("%s vs %s", val, this.name);
|
||||
if(StrEqual(val, this.name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
index = entry.FindKey("targetname");
|
||||
if(index != -1) {
|
||||
entry.Get(index, "", 0, val, sizeof(val));
|
||||
if(StrEqual(val, this.name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
delete entry;
|
||||
}
|
||||
Log("Warn: Could not find any matching lump for \"%s\" (type=%d)", this.name, this.type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Trigger() {
|
||||
int index = 0;
|
||||
EntityLumpEntry entry;
|
||||
while((index = this._findLumpIndex(index, entry) != -1)) {
|
||||
// for(int i = 0; i < entry.Length; i++) {
|
||||
// entry.Get(i, a, sizeof(a), v, sizeof(v));
|
||||
// Debug("%s=%s", a, v);
|
||||
// }
|
||||
this._trigger(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void _updateKey(EntityLumpEntry entry, const char[] key, const char[] value) {
|
||||
int index = entry.FindKey(key);
|
||||
if(index != -1) {
|
||||
Debug("update key %s = %s", key, value);
|
||||
entry.Update(index, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void _trigger(EntityLumpEntry entry) {
|
||||
if(StrEqual(this.action, "setclassname")) {
|
||||
this._updateKey(entry, "classname", this.value);
|
||||
}
|
||||
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
enum struct MapData {
|
||||
ArrayList scenes;
|
||||
ArrayList lumpEdits;
|
||||
ArrayList activeScenes;
|
||||
}
|
||||
|
||||
enum loadFlags {
|
||||
FLAG_NONE = 0,
|
||||
FLAG_ALL_SCENES = 1, // Pick all scenes, no random chance
|
||||
FLAG_ALL_VARIANTS = 2, // Pick all variants (for debug purposes),
|
||||
FLAG_REFRESH = 4, // Load data bypassing cache
|
||||
}
|
||||
|
||||
// Reads (mapname).json file and parses it
|
||||
public bool LoadMapData(const char[] map, int flags) {
|
||||
Debug("Loading config for %s", map);
|
||||
char filePath[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, filePath, sizeof(filePath), "data/randomizer/%s.json", map);
|
||||
if(!FileExists(filePath)) {
|
||||
|
@ -145,19 +391,24 @@ public bool LoadMap(const char[] map) {
|
|||
char buffer[65536];
|
||||
File file = OpenFile(filePath, "r");
|
||||
if(file == null) {
|
||||
LogError("[Randomizer] Could not open map config file (data/randomizer/%s.json)", map);
|
||||
LogError("Could not open map config file (data/randomizer/%s.json)", map);
|
||||
return false;
|
||||
}
|
||||
file.ReadString(buffer, sizeof(buffer));
|
||||
JSON_Object data = json_decode(buffer);
|
||||
if(data == null) {
|
||||
json_get_last_error(buffer, sizeof(buffer));
|
||||
LogError("[Randomizer] Could not parse map config file (data/randomizer/%s.json): %s", map, buffer);
|
||||
LogError("Could not parse map config file (data/randomizer/%s.json): %s", map, buffer);
|
||||
delete file;
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug("Starting parsing json data");
|
||||
|
||||
Cleanup();
|
||||
scenes = new ArrayList(sizeof(SceneData));
|
||||
g_MapData.scenes = new ArrayList(sizeof(SceneData));
|
||||
g_MapData.lumpEdits = new ArrayList(sizeof(LumpEditData));
|
||||
g_MapData.activeScenes.Clear();
|
||||
|
||||
Profiler profiler = new Profiler();
|
||||
profiler.Start();
|
||||
|
@ -166,30 +417,53 @@ public bool LoadMap(const char[] map) {
|
|||
char key[32];
|
||||
for (int i = 0; i < length; i += 1) {
|
||||
data.GetKey(i, key, sizeof(key));
|
||||
if(data.GetType(key) != JSON_Type_Object) continue;
|
||||
|
||||
JSON_Object scene = data.GetObject(key);
|
||||
// Parses scene data and inserts to scenes
|
||||
loadGroup(key, scene);
|
||||
if(key[0] == '_') {
|
||||
if(StrEqual(key, "_lumps")) {
|
||||
JSON_Array lumpsList = view_as<JSON_Array>(data.GetObject(key));
|
||||
if(lumpsList != null) {
|
||||
for(int l = 0; l < lumpsList.Length; l++) {
|
||||
loadLumpData(g_MapData.lumpEdits, lumpsList.GetObject(l));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Debug("Unknown special entry \"%s\", skipping", key);
|
||||
}
|
||||
} else {
|
||||
if(data.GetType(key) != JSON_Type_Object) {
|
||||
Debug("Invalid normal entry \"%s\" (not an object), skipping", key);
|
||||
continue;
|
||||
}
|
||||
JSON_Object scene = data.GetObject(key);
|
||||
// Parses scene data and inserts to scenes
|
||||
loadScene(key, scene);
|
||||
}
|
||||
}
|
||||
|
||||
profiler.Stop();
|
||||
Log("Loaded %d scenes in %.1f seconds", scenes.Length, profiler.Time);
|
||||
profiler.Start();
|
||||
|
||||
processGroups();
|
||||
|
||||
profiler.Stop();
|
||||
Log("Done processing in %.1f seconds", scenes.Length, profiler.Time);
|
||||
|
||||
json_cleanup_and_delete(data);
|
||||
|
||||
profiler.Stop();
|
||||
Log("Parsed map file and found %d scenes in %.4f seconds", g_MapData.scenes.Length, profiler.Time);
|
||||
delete profiler;
|
||||
delete file;
|
||||
return true;
|
||||
}
|
||||
|
||||
void loadGroup(const char key[MAX_SCENE_NAME_LENGTH], JSON_Object sceneData) {
|
||||
// Calls LoadMapData (read&parse (mapname).json) then select scenes
|
||||
public bool RunMap(const char[] map, int flags) {
|
||||
if(g_MapData.scenes == null || flags & view_as<int>(FLAG_REFRESH)) {
|
||||
LoadMapData(map, flags);
|
||||
}
|
||||
Profiler profiler = new Profiler();
|
||||
|
||||
profiler.Start();
|
||||
selectScenes(flags);
|
||||
profiler.Stop();
|
||||
|
||||
Log("Done processing in %.4f seconds", g_MapData.scenes.Length, profiler.Time);
|
||||
return true;
|
||||
}
|
||||
|
||||
void loadScene(const char key[MAX_SCENE_NAME_LENGTH], JSON_Object sceneData) {
|
||||
SceneData scene;
|
||||
scene.name = key;
|
||||
scene.chance = sceneData.GetFloat("chance");
|
||||
|
@ -197,46 +471,102 @@ void loadGroup(const char key[MAX_SCENE_NAME_LENGTH], JSON_Object sceneData) {
|
|||
LogError("Scene \"%s\" has invalid chance (%f)", scene.name, scene.chance);
|
||||
return;
|
||||
}
|
||||
scene.exclusions = new ArrayList(ByteCountToCells(MAX_SCENE_NAME_LENGTH));
|
||||
JSON_Array exclusions = view_as<JSON_Array>(sceneData.GetObject("exclusions"));
|
||||
if(exclusions != null) {
|
||||
char id[MAX_SCENE_NAME_LENGTH];
|
||||
for(int i = 0; i < exclusions.Length; i ++) {
|
||||
exclusions.GetString(i, id, sizeof(id));
|
||||
scene.exclusions.PushString(id);
|
||||
}
|
||||
}
|
||||
sceneData.GetString("group", scene.group, sizeof(scene.group));
|
||||
scene.variants = new ArrayList(sizeof(SceneVariantData));
|
||||
JSON_Array variants = view_as<JSON_Array>(sceneData.GetObject("variants"));
|
||||
for(int i = 0; i < variants.Length; i++) {
|
||||
// Parses choice and loads to scene.choices
|
||||
loadChoice(scene, variants.GetObject(i));
|
||||
}
|
||||
scenes.PushArray(scene);
|
||||
g_MapData.scenes.PushArray(scene);
|
||||
}
|
||||
|
||||
void loadChoice(SceneData scene, JSON_Object choiceData) {
|
||||
SceneVariantData choice;
|
||||
choice.weight = choiceData.GetInt("weight", 1);
|
||||
choice.entities = new ArrayList(sizeof(VariantEntityData));
|
||||
choice.inputsList = new ArrayList(sizeof(VariantInputData));
|
||||
JSON_Array entities = view_as<JSON_Array>(choiceData.GetObject("entities"));
|
||||
for(int i = 0; i < entities.Length; i++) {
|
||||
// Parses entities and loads to choice.entities
|
||||
loadChoiceEntity(choice, entities.GetObject(i));
|
||||
if(entities != null) {
|
||||
for(int i = 0; i < entities.Length; i++) {
|
||||
// Parses entities and loads to choice.entities
|
||||
loadChoiceEntity(choice.entities, entities.GetObject(i));
|
||||
}
|
||||
}
|
||||
JSON_Array inputsList = view_as<JSON_Array>(choiceData.GetObject("inputs"));
|
||||
if(inputsList != null) {
|
||||
for(int i = 0; i < inputsList.Length; i++) {
|
||||
loadChoiceInput(choice.inputsList, inputsList.GetObject(i));
|
||||
}
|
||||
}
|
||||
scene.variants.PushArray(choice);
|
||||
}
|
||||
|
||||
void loadChoiceEntity(SceneVariantData choice, JSON_Object entityData) {
|
||||
void loadChoiceInput(ArrayList list, JSON_Object inputData) {
|
||||
VariantInputData input;
|
||||
// Check classname -> targetname -> hammerid
|
||||
if(!inputData.GetString("classname", input.name, sizeof(input.name))) {
|
||||
if(inputData.GetString("targetname", input.name, sizeof(input.name))) {
|
||||
input.type = Input_Targetname;
|
||||
} else {
|
||||
if(inputData.GetString("hammerid", input.name, sizeof(input.name))) {
|
||||
input.type = Input_HammerId;
|
||||
} else {
|
||||
int id = inputData.GetInt("hammerid");
|
||||
if(id > 0) {
|
||||
input.type = Input_HammerId;
|
||||
IntToString(id, input.name, sizeof(input.name));
|
||||
} else {
|
||||
LogError("Missing valid input specification (hammerid, classname, targetname)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
inputData.GetString("input", input.input, sizeof(input.input));
|
||||
list.PushArray(input);
|
||||
}
|
||||
|
||||
void loadLumpData(ArrayList list, JSON_Object inputData) {
|
||||
LumpEditData input;
|
||||
// Check classname -> targetname -> hammerid
|
||||
if(!inputData.GetString("classname", input.name, sizeof(input.name))) {
|
||||
if(inputData.GetString("targetname", input.name, sizeof(input.name))) {
|
||||
input.type = Input_Targetname;
|
||||
} else {
|
||||
if(inputData.GetString("hammerid", input.name, sizeof(input.name))) {
|
||||
input.type = Input_HammerId;
|
||||
} else {
|
||||
int id = inputData.GetInt("hammerid");
|
||||
if(id > 0) {
|
||||
input.type = Input_HammerId;
|
||||
IntToString(id, input.name, sizeof(input.name));
|
||||
} else {
|
||||
LogError("Missing valid input specification (hammerid, classname, targetname)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
inputData.GetString("action", input.action, sizeof(input.action));
|
||||
inputData.GetString("value", input.value, sizeof(input.value));
|
||||
list.PushArray(input);
|
||||
}
|
||||
|
||||
void loadChoiceEntity(ArrayList list, JSON_Object entityData) {
|
||||
VariantEntityData entity;
|
||||
entityData.GetString("model", entity.model, sizeof(entity.model));
|
||||
if(!entityData.GetString("type", entity.type, sizeof(entity.type))) {
|
||||
entity.type = "prop_dynamic";
|
||||
} else if(entity.type[0] == '_') {
|
||||
LogError("Invalid custom entity type \"%s\"", entity.type);
|
||||
return;
|
||||
}
|
||||
GetVector(entityData, "origin", entity.origin);
|
||||
GetVector(entityData, "angles", entity.angles);
|
||||
GetVector(entityData, "scale", entity.scale);
|
||||
choice.entities.PushArray(entity);
|
||||
GetColor(entityData, "color", entity.color);
|
||||
list.PushArray(entity);
|
||||
}
|
||||
|
||||
void GetVector(JSON_Object obj, const char[] key, float out[3]) {
|
||||
|
@ -248,56 +578,175 @@ void GetVector(JSON_Object obj, const char[] key, float out[3]) {
|
|||
}
|
||||
}
|
||||
|
||||
void processGroups() {
|
||||
SceneData scene;
|
||||
for(int i = 0; i < scenes.Length; i++) {
|
||||
scenes.GetArray(i, scene);
|
||||
// TODO: Exclusions
|
||||
if(GetURandomFloat() < scene.chance) {
|
||||
selectScene(scene);
|
||||
}
|
||||
void GetColor(JSON_Object obj, const char[] key, int out[4]) {
|
||||
JSON_Array vecArray = view_as<JSON_Array>(obj.GetObject(key));
|
||||
if(vecArray != null) {
|
||||
out[0] = vecArray.GetInt(0);
|
||||
out[1] = vecArray.GetInt(1);
|
||||
out[2] = vecArray.GetInt(2);
|
||||
if(vecArray.Length == 4)
|
||||
out[3] = vecArray.GetInt(3);
|
||||
else
|
||||
out[3] = 255;
|
||||
} else {
|
||||
out[0] = 255;
|
||||
out[1] = 255;
|
||||
out[2] = 255;
|
||||
out[3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
void selectScene(SceneData scene) {
|
||||
// TODO: Weight
|
||||
void selectScenes(int flags = 0) {
|
||||
SceneData scene;
|
||||
StringMap groups = new StringMap();
|
||||
ArrayList list;
|
||||
for(int i = 0; i < g_MapData.scenes.Length; i++) {
|
||||
g_MapData.scenes.GetArray(i, scene);
|
||||
// TODO: Exclusions
|
||||
// Select scene if not in group, or add to list of groups
|
||||
if(scene.group[0] == '\0') {
|
||||
selectScene(scene, flags);
|
||||
} else {
|
||||
if(!groups.GetValue(scene.group, list)) {
|
||||
list = new ArrayList();
|
||||
}
|
||||
list.Push(i);
|
||||
groups.SetValue(scene.group, list);
|
||||
}
|
||||
}
|
||||
|
||||
StringMapSnapshot snapshot = groups.Snapshot();
|
||||
char key[MAX_SCENE_NAME_LENGTH];
|
||||
for(int i = 0; i < snapshot.Length; i++) {
|
||||
snapshot.GetKey(i, key, sizeof(key));
|
||||
groups.GetValue(key, list);
|
||||
int index = GetURandomInt() % list.Length;
|
||||
index = list.Get(index);
|
||||
g_MapData.scenes.GetArray(index, scene);
|
||||
Debug("Selected scene \"%s\" for group %s (%d members)", scene.name, key, list.Length);
|
||||
selectScene(scene, flags);
|
||||
delete list;
|
||||
}
|
||||
delete snapshot;
|
||||
delete groups;
|
||||
}
|
||||
|
||||
void selectScene(SceneData scene, int flags) {
|
||||
// Use the .chance field unless FLAG_ALL_SCENES is set
|
||||
if(~flags & view_as<int>(FLAG_ALL_SCENES) && GetURandomFloat() > scene.chance) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(scene.variants.Length == 0) {
|
||||
LogError("Warn: No variants were found for scene \"%s\"", scene.name);
|
||||
return;
|
||||
}
|
||||
Debug("Selected scene: \"%s\"", scene.name);
|
||||
|
||||
ArrayList choices = new ArrayList();
|
||||
SceneVariantData choice;
|
||||
int index;
|
||||
// Weighted random: Push N times dependent on weight
|
||||
for(int i = 0; i < scene.variants.Length; i++) {
|
||||
scene.variants.GetArray(i, choice);
|
||||
for(int c = 0; c < choice.weight; c++) {
|
||||
choices.Push(i);
|
||||
if(flags & view_as<int>(FLAG_ALL_VARIANTS)) {
|
||||
spawnVariant(choice);
|
||||
} else {
|
||||
for(int c = 0; c < choice.weight; c++) {
|
||||
choices.Push(i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
int index = GetURandomInt() % choices.Length;
|
||||
index = choices.Get(index);
|
||||
delete choices;
|
||||
Debug("Selected variant: #%d", index);
|
||||
scene.variants.GetArray(index, choice);
|
||||
spawnVariant(choice);
|
||||
if(flags & view_as<int>(FLAG_ALL_VARIANTS)) {
|
||||
delete choices;
|
||||
} else {
|
||||
index = GetURandomInt() % choices.Length;
|
||||
index = choices.Get(index);
|
||||
delete choices;
|
||||
Log("Spawned scene \"%s\" with variant #%d", scene.name, index);
|
||||
scene.variants.GetArray(index, choice);
|
||||
spawnVariant(choice);
|
||||
}
|
||||
|
||||
ActiveSceneData aScene;
|
||||
strcopy(aScene.name, sizeof(aScene.name), scene.name);
|
||||
aScene.variantIndex = index;
|
||||
g_MapData.activeScenes.PushArray(aScene);
|
||||
}
|
||||
|
||||
void spawnVariant(SceneVariantData choice) {
|
||||
VariantEntityData entity;
|
||||
// Weighted random: Push N times dependent on weight
|
||||
for(int i = 0; i < choice.entities.Length; i++) {
|
||||
choice.entities.GetArray(i, entity);
|
||||
spawnEntity(entity);
|
||||
}
|
||||
|
||||
if(choice.inputsList.Length > 0) {
|
||||
VariantInputData input;
|
||||
for(int i = 0; i < choice.inputsList.Length; i++) {
|
||||
choice.inputsList.GetArray(i, input);
|
||||
input.Trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spawnEntity(VariantEntityData entity) {
|
||||
Debug("spawning \"%s\" at (%.1f %.1f %.1f) rot (%.0f %.0f %.0f)", entity.model, entity.origin[0], entity.origin[1], entity.origin[2], entity.angles[0], entity.angles[1], entity.angles[2]);
|
||||
PrecacheModel(entity.model);
|
||||
CreateProp(entity.type, entity.model, entity.origin, entity.angles);
|
||||
if(StrEqual(entity.type, "env_fire")) {
|
||||
Debug("spawning \"%s\" at (%.1f %.1f %.1f) rot (%.0f %.0f %.0f)", entity.type, entity.origin[0], entity.origin[1], entity.origin[2], entity.angles[0], entity.angles[1], entity.angles[2]);
|
||||
CreateFire(entity.origin, 20.0, 100.0, 0.0);
|
||||
} else if(StrEqual(entity.type, "env_physics_blocker") || StrEqual(entity.type, "env_player_blocker")) {
|
||||
CreateEnvBlockerScaled(entity.type, entity.origin, entity.scale);
|
||||
} else if(StrEqual(entity.type, "infodecal")) {
|
||||
CreateDecal(entity.model, entity.origin);
|
||||
} else if(StrContains(entity.type, "prop_") == 0) {
|
||||
if(entity.model[0] == '\0') {
|
||||
LogError("Missing model for entity with type \"%s\"", entity.type);
|
||||
return;
|
||||
}
|
||||
PrecacheModel(entity.model);
|
||||
int prop = CreateProp(entity.type, entity.model, entity.origin, entity.angles);
|
||||
SetEntityRenderColor(prop, entity.color[0], entity.color[1], entity.color[2], entity.color[3]);
|
||||
} else if(StrEqual(entity.type, "hammerid")) {
|
||||
int targetId = StringToInt(entity.model);
|
||||
if(targetId > 0) {
|
||||
int ent = -1;
|
||||
while((ent = FindEntityByClassname(ent, "*")) != INVALID_ENT_REFERENCE) {
|
||||
int hammerId = GetEntProp(ent, Prop_Data, "m_iHammerID");
|
||||
if(hammerId == targetId) {
|
||||
Debug("moved entity (hammerid=%d) to %.0f %.0f %.0f rot %.0f %.0f %.0f", targetId, entity.origin[0], entity.origin[1], entity.origin[2], entity.angles[0], entity.angles[1], entity.angles[2]);
|
||||
TeleportEntity(ent, entity.origin, entity.angles, NULL_VECTOR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Debug("Warn: Could not find entity (hammerid=%d) (model=%s)", targetId, entity.model);
|
||||
} else if(StrEqual(entity.type, "targetname")) {
|
||||
int ent = -1;
|
||||
char targetname[64];
|
||||
bool found = false;
|
||||
while((ent = FindEntityByClassname(ent, "*")) != INVALID_ENT_REFERENCE) {
|
||||
GetEntPropString(ent, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
||||
if(StrEqual(entity.model, targetname)) {
|
||||
Debug("moved entity (targetname=%s) to %.0f %.0f %.0f rot %.0f %.0f %.0f", entity.model, entity.origin[0], entity.origin[1], entity.origin[2], entity.angles[0], entity.angles[1], entity.angles[2]);
|
||||
TeleportEntity(ent, entity.origin, entity.angles, NULL_VECTOR);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
Debug("Warn: Could not find entity (targetname=%s)", entity.model);
|
||||
} else if(StrEqual(entity.type, "classname")) {
|
||||
int ent = -1;
|
||||
char classname[64];
|
||||
bool found;
|
||||
while((ent = FindEntityByClassname(ent, classname)) != INVALID_ENT_REFERENCE) {
|
||||
Debug("moved entity (classname=%s) to %.0f %.0f %.0f rot %.0f %.0f %.0f", entity.model, entity.origin[0], entity.origin[1], entity.origin[2], entity.angles[0], entity.angles[1], entity.angles[2]);
|
||||
TeleportEntity(ent, entity.origin, entity.angles, NULL_VECTOR);
|
||||
found = true;
|
||||
}
|
||||
if(!found)
|
||||
Debug("Warn: Could not find entity (classname=%s)", entity.model);
|
||||
} else {
|
||||
LogError("Unknown entity type \"%s\"", entity.type);
|
||||
}
|
||||
}
|
||||
|
||||
void Debug(const char[] format, any ...) {
|
||||
|
@ -321,12 +770,16 @@ void Log(const char[] format, any ...) {
|
|||
}
|
||||
|
||||
void Cleanup() {
|
||||
if(scenes != null) {
|
||||
if(g_MapData.scenes != null) {
|
||||
SceneData scene;
|
||||
for(int i = 0; i < scenes.Length; i++) {
|
||||
scenes.GetArray(i, scene);
|
||||
for(int i = 0; i < g_MapData.scenes.Length; i++) {
|
||||
g_MapData.scenes.GetArray(i, scene);
|
||||
scene.Cleanup();
|
||||
}
|
||||
delete scenes;
|
||||
delete g_MapData.scenes;
|
||||
}
|
||||
delete g_MapData.lumpEdits;
|
||||
|
||||
DeleteCustomEnts();
|
||||
g_MapData.activeScenes.Clear();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue