diff --git a/scripting/include/gamemodes/ents.inc b/scripting/include/gamemodes/ents.inc index eb48c6f..664d046 100644 --- a/scripting/include/gamemodes/ents.inc +++ b/scripting/include/gamemodes/ents.inc @@ -46,7 +46,7 @@ stock int CreateEnvBlockerScaled(const char[] entClass, const float pos[3], cons int entity = CreateEntityByName(entClass); DispatchKeyValue(entity, "targetname", ENT_BLOCKER_NAME); DispatchKeyValue(entity, "initialstate", "1"); - DispatchKeyValue(entity, "BlockType", "0"); + DispatchKeyValueInt(entity, "BlockType", StrEqual(entClass, "env_physics_blocker") ? 4 : 0); static float mins[3]; mins = scale; NegateVector(mins); @@ -160,11 +160,12 @@ stock void ClearPortalData() { portals.Clear(); } -stock int StartPropCreate(const char[] entClass, const char[] model, const float pos[3], const float ang[3] = NULL_VECTOR, const float vel[3] = NULL_VECTOR) { +stock int StartPropCreate(const char[] entClass, const char[] model, const float pos[3], const float ang[3] = NULL_VECTOR, const float vel[3] = NULL_VECTOR, bool hasCollision = true) { int entity = CreateEntityByName(entClass); if(entity == -1) return -1; DispatchKeyValue(entity, "model", model); - DispatchKeyValue(entity, "solid", "6"); + if(hasCollision) + DispatchKeyValue(entity, "solid", "6"); DispatchKeyValue(entity, "targetname", ENT_PROP_NAME); DispatchKeyValue(entity, "disableshadows", "1"); TeleportEntity(entity, pos, ang, vel); diff --git a/scripting/include/randomizer/defs.sp b/scripting/include/randomizer/defs.sp index 74651f4..44a32ea 100644 --- a/scripting/include/randomizer/defs.sp +++ b/scripting/include/randomizer/defs.sp @@ -266,11 +266,124 @@ enum struct SceneVariantData { void Cleanup() { delete this.inputsList; + VariantEntityData entity; + for(int i = 0; i < this.entities.Length; i++) { + this.entities.GetArray(i, entity, sizeof(entity)); + entity.Cleanup(); + } delete this.entities; delete this.forcedScenes; } } +enum propertyType { + PROPERTY_NONE = -1, + PROPERTY_STRING, + PROPERTY_INTEGER, + PROPERTY_FLOAT +} + +// This is horrible but we need a way to know what the type of the netprop to set is +enum struct PropertyStore { + JSONObject intKv; + JSONObject stringKv; + JSONObject floatKv; + + void Cleanup() { + if(this.intKv != null) delete this.intKv; + if(this.stringKv != null) delete this.stringKv; + if(this.floatKv != null) delete this.floatKv; + } + + bool GetInt(const char[] name, int &value) { + if(this.intKv == null) return false; + if(!this.intKv.HasKey(name)) return false; + value = this.intKv.GetInt(name); + return true; + } + + bool GetString(const char[] name, char[] buffer, int maxlen) { + if(this.stringKv == null) return false; + if(!this.stringKv.HasKey(name)) return false; + this.stringKv.GetString(name, buffer, maxlen); + return true; + } + + bool GetFloat(const char[] name, float &value) { + if(this.floatKv == null) return false; + if(!this.floatKv.HasKey(name)) return false; + value = this.floatKv.GetFloat(name); + return true; + } + + propertyType GetPropertyType(const char[] key) { + if(this.intKv != null && this.intKv.HasKey(key)) return PROPERTY_INTEGER; + if(this.floatKv != null && this.floatKv.HasKey(key)) return PROPERTY_FLOAT; + if(this.stringKv != null && this.stringKv.HasKey(key)) return PROPERTY_STRING; + return PROPERTY_NONE; + } + + bool HasAny() { + return this.intKv != null || this.floatKv != null || this.stringKv != null; + } + + ArrayList Keys() { + char key[128]; + ArrayList list = new ArrayList(ByteCountToCells(128)); + JSONObjectKeys keys; + if(this.stringKv != null) { + keys = this.stringKv.Keys() + while(keys.ReadKey(key, sizeof(key))) { + list.PushString(key); + } + delete keys; + } + if(this.intKv != null) { + keys = this.intKv.Keys() + while(keys.ReadKey(key, sizeof(key))) { + list.PushString(key); + } + delete keys; + } + if(this.floatKv != null) { + keys = this.floatKv.Keys() + while(keys.ReadKey(key, sizeof(key))) { + list.PushString(key); + } + delete keys; + } + return list; + } + + StringMap Entries() { + char key[128]; + StringMap kv = new StringMap(); + JSONObjectKeys keys; + if(this.stringKv != null) { + keys = this.stringKv.Keys() + while(keys.ReadKey(key, sizeof(key))) { + kv.SetValue(key, PROPERTY_STRING); + } + delete keys; + } + if(this.intKv != null) { + keys = this.intKv.Keys() + while(keys.ReadKey(key, sizeof(key))) { + kv.SetValue(key, PROPERTY_INTEGER); + } + delete keys; + } + if(this.floatKv != null) { + keys = this.floatKv.Keys() + while(keys.ReadKey(key, sizeof(key))) { + kv.SetValue(key, PROPERTY_FLOAT); + } + delete keys; + } + return kv; + } +} + enum struct VariantEntityData { char type[32]; char model[128]; @@ -281,6 +394,54 @@ enum struct VariantEntityData { int color[4]; ArrayList keyframes; + PropertyStore properties; + JSONObject propertiesInt; + JSONObject propertiesString; + JSONObject propertiesFloat; + + void Cleanup() { + if(this.keyframes != null) { + delete this.keyframes; + } + this.properties.Cleanup(); + } + + void ApplyProperties(int entity) { + if(!this.properties.HasAny()) return; + char key[64], buffer[128]; + ArrayList keys = this.properties.Keys(); + for(int i = 0; i < keys.Length; i++) { + keys.GetString(i, key, sizeof(key)); + // Only want to apply netprops (m_ prefix) + if(key[0] == 'm' && key[1] == '_') { + propertyType type = this.properties.GetPropertyType(key); + Debug("netprop %s type %d", key, type); + switch(type) { + case PROPERTY_STRING: { + this.properties.GetString(key, buffer, sizeof(buffer)); + Debug("Applying netprop %s (val=%s) on %d", key, buffer, entity); + SetEntPropString(entity, Prop_Send, key, buffer); + break; + } + case PROPERTY_INTEGER: { + int val; + this.properties.GetInt(key, val); + Debug("Applying netprop %s (val=%d) on %d", key, val, entity); + SetEntProp(entity, Prop_Send, key, val); + break; + } + case PROPERTY_FLOAT: { + float val; + this.properties.GetFloat(key, val); + Debug("Applying netprop %s (val=%f) on %d", key, val, entity); + SetEntPropFloat(entity, Prop_Send, key, val); + break; + } + } + } + } + delete keys; + } } enum InputType { diff --git a/scripting/include/randomizer/loader_functions.sp b/scripting/include/randomizer/loader_functions.sp index 90f010e..dcf8b93 100644 --- a/scripting/include/randomizer/loader_functions.sp +++ b/scripting/include/randomizer/loader_functions.sp @@ -258,5 +258,11 @@ void loadChoiceEntity(ArrayList list, JSONObject entityData) { GetVector(entityData, "angles", entity.angles); GetVector(entityData, "scale", entity.scale); GetColor(entityData, "color", entity.color, DEFAULT_COLOR); + if(entityData.HasKey("properties")) { + JSONObject propRoot = view_as(entityData.Get("properties")); + if(propRoot.HasKey("int")) entity.properties.intKv = view_as(propRoot.Get("int")); + if(propRoot.HasKey("float")) entity.properties.floatKv = view_as(propRoot.Get("float")); + if(propRoot.HasKey("string")) entity.properties.stringKv = view_as(propRoot.Get("string")); + } list.PushArray(entity); } \ No newline at end of file diff --git a/scripting/l4d2_randomizer.sp b/scripting/l4d2_randomizer.sp index 8eabb43..6e60c7a 100644 --- a/scripting/l4d2_randomizer.sp +++ b/scripting/l4d2_randomizer.sp @@ -240,7 +240,14 @@ public Action Command_CycleRandom(int client, int args) { if(flags < 0) { ReplyToCommand(client, "Invalid flags"); } else { - LoadRunGlobalMap(currentMap, flags | view_as(FLAG_REFRESH)); + if(args > 1) { + char buffer[64]; + GetCmdArg(2, buffer, sizeof(buffer)); + LoadRunGlobalMap(buffer, flags | view_as(FLAG_REFRESH)); + PrintCenterText(client, "Cycled %s flags=%d", buffer, flags); + } else { + LoadRunGlobalMap(currentMap, flags | view_as(FLAG_REFRESH)); + } if(client > 0) PrintCenterText(client, "Cycled flags=%d", flags); } @@ -461,7 +468,7 @@ Action Command_RandomizerBuild(int client, int args) { } float pos[3]; float scale[3] = { 15.0, 30.0, 100.0 }; - GetLookingPosition(client, Filter_IgnorePlayer, pos); + GetClientAbsOrigin(client, pos); JSONObject obj = new JSONObject(); obj.SetString("type", "env_player_blocker"); obj.Set("origin", FromFloatArray(pos, 3)); @@ -749,6 +756,11 @@ void AddGascanSpawner(VariantEntityData data) { } void spawnEntity(VariantEntityData entity) { + // if(entity.type[0] == '_') { + // if(StrEqual(entity.type, "_gascan")) { + // AddGascanSpawner(entity); + // } + // } if(StrEqual(entity.type, "_gascan")) { AddGascanSpawner(entity); } else if(StrEqual(entity.type, "env_fire")) { @@ -772,6 +784,17 @@ void spawnEntity(VariantEntityData entity) { } 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]); + entity.ApplyProperties(prop); + } else if(StrContains(entity.type, "weapon_") == 0) { + if(entity.model[0] == '\0') { + LogError("Missing model for entity with type \"%s\"", entity.type); + return; + } else if(!PrecacheModel(entity.model)) { + LogError("Precache of entity model \"%s\" with type \"%s\" failed", entity.model, entity.type); + return; + } + 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) {