diff --git a/scripting/include/hats/walls.sp b/scripting/include/hats/editor.sp similarity index 80% rename from scripting/include/hats/walls.sp rename to scripting/include/hats/editor.sp index 11a9458..868b810 100644 --- a/scripting/include/hats/walls.sp +++ b/scripting/include/hats/editor.sp @@ -1,6 +1,7 @@ int BUILDER_COLOR[4] = { 0, 255, 0, 235 }; int GLOW_BLUE[4] = { 3, 148, 252 }; -int GLOW_RED[4] = { 255, 0, 0, 235 }; +int GLOW_RED_ALPHA[4] = { 255, 0, 0, 235 }; +int GLOW_RED[3] = { 255, 0, 0}; int GLOW_WHITE[4] = { 255, 255, 255, 255 }; int GLOW_GREEN[4] = { 3, 252, 53 }; float ORIGIN_SIZE[3] = { 2.0, 2.0, 2.0 }; @@ -46,9 +47,14 @@ char COLOR_INDEX[4] = "RGBA"; ArrayList createdWalls; enum struct WallBuilderData { + char classname[32]; + char data[32]; + float origin[3]; - float mins[3]; + float prevOrigin[3]; float angles[3]; + float prevAngles[3]; + float mins[3]; float size[3]; int color[4]; int colorIndex; @@ -58,6 +64,7 @@ enum struct WallBuilderData { float moveDistance; int entity; bool hasCollision; + bool hasCollisionRotate; editMode mode; buildType buildType; @@ -70,6 +77,7 @@ enum struct WallBuilderData { RemoveEntity(this.entity); } this.entity = INVALID_ENT_REFERENCE; + this.data[0] = '\0'; this.size[0] = this.size[1] = this.size[2] = 5.0; this.angles[0] = this.angles[1] = this.angles[2] = 0.0; this.color[0] = this.color[1] = this.color[2] = this.color[3] = 255; @@ -77,8 +85,10 @@ enum struct WallBuilderData { this.axis = 1; this.moveDistance = 200.0; this.hasCollision = true; + this.hasCollisionRotate = false; this.flags = Edit_None; this.buildType = Build_Solid; + this.classname[0] = '\0'; this.CalculateMins(); this.SetMode(INACTIVE); if(initial) { @@ -130,6 +140,10 @@ enum struct WallBuilderData { this.mode = mode; } + void SetData(const char[] data) { + strcopy(this.data, sizeof(this.data), data); + } + void CycleMode(int client, float tick) { if(tick - cmdThrottle[client] <= 0.25) return; int flags = GetEntityFlags(client) & ~FL_FROZEN; @@ -157,7 +171,6 @@ enum struct WallBuilderData { } case FREELOOK: { this.mode = MOVE_ORIGIN; - // PrintToChat(client, "Hold \x04USE (E)\x01 to rotate, \x04WALK (SHIFT)\x01 to change speed"); } } PrintToChat(client, "\x04[Editor]\x01 Mode: \x05%s\x01 (Press \x04RELOAD\x01 to change mode)", MODE_NAME[this.mode]); @@ -174,6 +187,16 @@ enum struct WallBuilderData { cmdThrottle[client] = tick; } + void ToggleCollisionRotate(int client, float tick) { + if(tick - cmdThrottle[client] <= 0.25) return; + this.hasCollisionRotate = !this.hasCollisionRotate + if(this.hasCollisionRotate) + PrintToChat(client, "\x04[Editor]\x01 Rotate with Collision: \x05ON\x01"); + else + PrintToChat(client, "\x04[Editor]\x01 Rotate with Collision: \x04OFF\x01"); + cmdThrottle[client] = tick; + } + void CycleAxis(int client, float tick) { if(tick - cmdThrottle[client] <= 0.15) return; if(this.axis == 0) { @@ -199,9 +222,9 @@ enum struct WallBuilderData { case 90: this.snapAngle = 1; } - this.angles[0] = SnapTo(this.angles[0], float(this.snapAngle)); - this.angles[1] = SnapTo(this.angles[1], float(this.snapAngle)); - this.angles[2] = SnapTo(this.angles[2], float(this.snapAngle)); + // this.angles[0] = SnapTo(this.angles[0], float(this.snapAngle)); + // this.angles[1] = SnapTo(this.angles[1], float(this.snapAngle)); + // this.angles[2] = SnapTo(this.angles[2], float(this.snapAngle)); if(this.snapAngle == 1) PrintToChat(client, "\x04[Editor]\x01 Rotate Snap Degrees: \x04(OFF)\x01", this.snapAngle); @@ -220,7 +243,9 @@ enum struct WallBuilderData { void CycleBuildType(int client) { // No tick needed, is handled externally - if(this.buildType == Build_Physics) { + if(this.classname[0] != '\0') { + PrintToChat(client, "\x04[Editor]\x01 Spawn as: \x05%s\x01 (fixed)", this.classname); + } else if(this.buildType == Build_Physics) { this.buildType = Build_Solid; PrintToChat(client, "\x04[Editor]\x01 Spawn as: \x05Solid\x01"); } else if(this.buildType == Build_Solid) { @@ -302,22 +327,46 @@ enum struct WallBuilderData { return true; } - bool _FinishPreview(int& entity) { - entity = -1; - if(this.buildType == Build_Physics) + int _CreateWeapon() { + int entity = -1; + if(StrEqual(this.classname, "weapon_melee")) { + entity = CreateEntityByName("weapon_melee"); + DispatchKeyValue(entity, "melee_weapon", this.data); + } else { + entity = CreateEntityByName(this.data); + DispatchKeyValue(entity, "spawnflags", "8"); + } + return entity; + } + + int _CreateRegular() { + int entity = -1; + if(this.classname[0] != '\0') { + entity = CreateEntityByName(this.classname); + } else if(this.buildType == Build_Physics) entity = CreateEntityByName("prop_physics"); else - entity = CreateEntityByName("prop_dynamic"); + entity = CreateEntityByName("prop_dynamic_override"); if(entity == -1) return false; char model[128]; GetEntPropString(this.entity, Prop_Data, "m_ModelName", model, sizeof(model)); DispatchKeyValue(entity, "model", model); - DispatchKeyValue(entity, "targetname", "prop_preview"); if(this.buildType == Build_NonSolid) DispatchKeyValue(entity, "solid", "0"); else DispatchKeyValue(entity, "solid", "6"); + return entity; + } + + bool _FinishPreview(int& entity) { + if(StrContains(this.classname, "weapon") > -1) { + entity = this._CreateWeapon(); + } else { + entity = this._CreateRegular(); + } + + DispatchKeyValue(entity, "targetname", "propspawner_prop"); TeleportEntity(entity, this.origin, this.angles, NULL_VECTOR); if(!DispatchSpawn(entity)) { return false; @@ -351,8 +400,6 @@ enum struct WallBuilderData { DispatchKeyValue(entity, "solid", "6"); DispatchSpawn(entity); - // SetEntProp(entity, Prop_Send, "m_CollisionGroup", 1); - // SetEntProp(entity, Prop_Send, "m_nSolidType", 6); TeleportEntity(entity, this.origin, this.angles, NULL_VECTOR); this.entity = entity; this.flags |= Edit_Copy; @@ -364,12 +411,62 @@ enum struct WallBuilderData { this.flags |= Edit_WallCreator; } - bool PreviewModel(const char[] model) { - // If last entity was preview, kill it - PrecacheModel(model); + bool PreviewWeapon(const char[] classname) { + return false; + int entity; + // Melee weapons don't have weapon_ prefix this.Reset(); - int entity = CreateEntityByName("prop_dynamic"); - if(entity == -1) return false; + this.SetData(classname); + if(StrContains(classname, "weapon_") == -1) { + // no weapon_ prefix, its a melee + PrintToServer("Spawning weapon_melee: %s", classname); + entity = CreateEntityByName("weapon_melee"); + if(entity == -1) return false; + DispatchKeyValue(entity, "melee_weapon", classname); + strcopy(this.classname, sizeof(this.classname), "weapon_melee"); + } else { + PrintToServer("Spawning normal weapon: %s", classname); + entity = CreateEntityByName(classname); + if(entity == -1) return false; + DispatchKeyValue(entity, "spawnflags", "8"); + strcopy(this.classname, sizeof(this.classname), "weapon"); + } + DispatchKeyValue(entity, "targetname", "prop_preview"); + DispatchKeyValue(entity, "rendercolor", "255 128 255"); + DispatchKeyValue(entity, "renderamt", "200"); + DispatchKeyValue(entity, "rendermode", "1"); + if(!DispatchSpawn(entity)) { + PrintToServer("Failed to spawn"); + return false; + } + this.entity = entity; + this.flags |= (Edit_Copy | Edit_Preview); + this.SetMode(MOVE_ORIGIN); + // Seems some entities fail here: + return IsValidEntity(entity); + } + + bool PreviewModel(const char[] model, const char[] classname = "") { + // Check for an invalid model + if(StrEqual(classname, "_weapon") || StrEqual(classname, "_melee")) { + return this.PreviewWeapon(model); + } + if(PrecacheModel(model) == 0) { + PrintToServer("Invalid model: %s", model); + return false; + } + this.Reset(); + int entity = CreateEntityByName("prop_door_rotating"); + if(classname[0] == '\0') { + entity = CreateEntityByName("prop_dynamic_override"); + } else { + strcopy(this.classname, sizeof(this.classname), classname); + entity = CreateEntityByName(classname); + } + if(entity == -1) { + PrintToServer("Invalid classname: %s", classname); + return false; + } DispatchKeyValue(entity, "model", model); DispatchKeyValue(entity, "targetname", "prop_preview"); DispatchKeyValue(entity, "solid", "0"); @@ -377,6 +474,7 @@ enum struct WallBuilderData { DispatchKeyValue(entity, "renderamt", "200"); DispatchKeyValue(entity, "rendermode", "1"); if(!DispatchSpawn(entity)) { + PrintToServer("Failed to spawn"); return false; } this.entity = entity; @@ -390,6 +488,8 @@ enum struct WallBuilderData { this.Reset(); GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin); GetEntPropVector(entity, Prop_Send, "m_angRotation", this.angles); + this.prevOrigin = this.origin; + this.prevAngles = this.angles; GetEntPropVector(entity, Prop_Send, "m_vecMins", this.mins); GetEntPropVector(entity, Prop_Send, "m_vecMaxs", this.size); if(!makeCopy) { @@ -402,62 +502,15 @@ enum struct WallBuilderData { // Delete any copies: if(this.flags & Edit_Copy || this.flags & Edit_Preview) { RemoveEntity(this.entity); + } else if(~this.flags & Edit_WallCreator) { + // Is an edit of a prop + TeleportEntity(this.entity, this.prevOrigin, this.prevAngles, NULL_VECTOR); } this.SetMode(INACTIVE); } - - // void OpenSettings(int client) { - // Menu menu = new Menu(SettingsHandler); - // menu.AddItem("color", "Change Color"); - // menu.AddItem("type", "Change Spawn Type"); - // // if(this.flags & Edit_Scale) - // menu.ExitButton = true; - // // Only show back if we are for a preview - // menu.ExitBackButton = (this.flags & Edit_Preview) != 0; - // menu.Display(client, MENU_TIME_FOREVER); - // } } -WallBuilderData WallBuilder[MAXPLAYERS+1]; - -// int SettingsHandler(Menu menu, MenuAction action, int client, int param2) { -// if (action == MenuAction_Select) { -// char info[8]; -// menu.GetItem(param2, info, sizeof(info)); -// if(StrEqual(info, "color")) { -// Menu newMenu = new Menu(ColorHandler); -// newMenu.AddItem() -// } else if(StrEqual(info, "type")) { - -// } else { -// CPrintToChat(client, "\x04[Editor]\x01 Error: Unknown setting \x05%s", info); -// } - -// // Re-open category list when done editing setting -// if(WallBuilder[client].flags & Edit_Preview) { -// ShowItemMenu(client, g_lastCategoryIndex[client]); -// } -// } else if(action == MenuAction_Cancel) { -// if(WallBuilder[client].flags & Edit_Preview) { -// ShowItemMenu(client, g_lastCategoryIndex[client]); -// } -// } else if (action == MenuAction_End) -// delete menu; -// return 0; -// } - -// int ColorHandler(Menu menu, MenuAction action, int client, int param2) { -// if (action == MenuAction_Select) { -// char info[8]; - -// } else if(action == MenuAction_Cancel) { -// if(WallBuilder[client].flags & Edit_Preview) { -// ShowItemMenu(client, g_lastCategoryIndex[client]); -// } -// } else if (action == MenuAction_End) -// delete menu; -// return 0; -// } +WallBuilderData Editor[MAXPLAYERS+1]; Action OnWallClicked(int entity, int activator, int caller, UseType type, float value) { int wallId = FindWallId(entity); @@ -474,10 +527,10 @@ Action OnWallClicked(int entity, int activator, int caller, UseType type, float // TODO: Stacker, copy tool, new command? public Action Command_MakeWall(int client, int args) { - if(WallBuilder[client].IsActive()) { + if(Editor[client].IsActive()) { ReplyToCommand(client, "\x04[Editor]\x01 You are currently editing an entity. Finish editing your current entity with with \x05/edit done\x01 or cancel with \x04/edit cancel\x01"); } else { - WallBuilder[client].StartWall(); + Editor[client].StartWall(); if(args > 0) { // Get values for X, Y and Z axis (defaulting to 1.0): char arg2[8]; @@ -487,7 +540,7 @@ public Action Command_MakeWall(int client, int args) { if(StringToFloatEx(arg2, value) == 0) { value = 1.0; } - WallBuilder[client].size[i] = value; + Editor[client].size[i] = value; } float rot[3]; @@ -495,23 +548,24 @@ public Action Command_MakeWall(int client, int args) { // Flip X and Y depending on rotation // TODO: Validate if(rot[2] > 45 && rot[2] < 135 || rot[2] > -135 && rot[2] < -45) { - float temp = WallBuilder[client].size[0]; - WallBuilder[client].size[0] = WallBuilder[client].size[1]; - WallBuilder[client].size[1] = temp; + float temp = Editor[client].size[0]; + Editor[client].size[0] = Editor[client].size[1]; + Editor[client].size[1] = temp; } - WallBuilder[client].CalculateMins(); + Editor[client].CalculateMins(); } - WallBuilder[client].SetMode(SCALE); - GetCursorLimited(client, 100.0, WallBuilder[client].origin, Filter_IgnorePlayer); + Editor[client].SetMode(SCALE); + GetCursorLimited(client, 100.0, Editor[client].origin, Filter_IgnorePlayer); PrintToChat(client, "\x04[Editor]\x01 New Wall Started. End with \x05/wall build\x01 or \x04/wall cancel\x01"); PrintToChat(client, "\x04[Editor]\x01 Mode: \x05Scale\x01"); } return Plugin_Handled; } -public Action Command_ManageWalls(int client, int args) { +// TODO: move wall ids to own subcommand +Action Command_Editor(int client, int args) { if(args == 0) { PrintToChat(client, "\x04[Editor]\x01 Created Walls: \x05%d\x01", createdWalls.Length); for(int i = 1; i <= createdWalls.Length; i++) { @@ -528,7 +582,7 @@ public Action Command_ManageWalls(int client, int args) { SetEntityFlags(client, flags); int entity; - CompleteType result = WallBuilder[client].Create(entity); + CompleteType result = Editor[client].Create(entity); switch(result) { case Complete_WallSuccess: { if(entity > 0) @@ -548,10 +602,10 @@ public Action Command_ManageWalls(int client, int args) { } else if(StrEqual(arg1, "cancel")) { int flags = GetEntityFlags(client) & ~FL_FROZEN; SetEntityFlags(client, flags); - WallBuilder[client].Cancel(); - if(WallBuilder[client].flags & Edit_Preview) - PrintToChat(client, "\x04[Editor]\x01 Prop Spawer: \x04Done\x01"); - else if(WallBuilder[client].flags & Edit_WallCreator) { + Editor[client].Cancel(); + if(Editor[client].flags & Edit_Preview) + PrintToChat(client, "\x04[Editor]\x01 Prop Spawer: \x04Cancelled\x01"); + else if(Editor[client].flags & Edit_WallCreator) { PrintToChat(client, "\x04[Editor]\x01 Wall Creation: \x04Cancelled\x01"); } else { PrintToChat(client, "\x04[Editor]\x01 Entity Edit: \x04Cancelled\x01"); @@ -559,11 +613,11 @@ public Action Command_ManageWalls(int client, int args) { } else if(StrEqual(arg1, "export")) { // TODO: support exp #id float origin[3], angles[3], size[3]; - if(WallBuilder[client].IsActive()) { - origin = WallBuilder[client].origin; - angles = WallBuilder[client].angles; - size = WallBuilder[client].size; - Export(client, arg2, WallBuilder[client].entity, origin, angles, size); + if(Editor[client].IsActive()) { + origin = Editor[client].origin; + angles = Editor[client].angles; + size = Editor[client].size; + Export(client, arg2, Editor[client].entity, origin, angles, size); } else { int id = GetWallId(client, arg2); if(id == -1) return Plugin_Handled; @@ -574,16 +628,14 @@ public Action Command_ManageWalls(int client, int args) { GetEntPropVector(entity, Prop_Send, "m_vecMaxs", size); Export(client, arg2, entity, origin, angles, size); } - - } else if(StrEqual(arg1, "delete")) { - if(WallBuilder[client].IsActive() && args == 1) { - int entity = WallBuilder[client].entity; + if(Editor[client].IsActive() && args == 1) { + int entity = Editor[client].entity; if(IsValidEntity(entity)) { PrintToChat(client, "\x04[Editor]\x01 You are not editing any existing entity, use \x05/wall cancel\x01 to stop or \x05/wall delete "); } else if(entity > MaxClients) { RemoveEntity(entity); - WallBuilder[client].Reset(); + Editor[client].Reset(); PrintToChat(client, "\x04[Editor]\x01 Deleted current entity"); } else { PrintToChat(client, "\x04[Editor]\x01 Cannot delete player entities."); @@ -651,14 +703,14 @@ public Action Command_ManageWalls(int client, int args) { int id = GetWallId(client, arg2); if(id > -1) { int entity = GetWallEntity(id); - WallBuilder[client].Import(entity); + Editor[client].Import(entity); PrintToChat(client, "\x04[Editor]\x01 Editing wall \x05%d\x01. End with \x05/wall done\x01 or \x04/wall cancel\x01", id); PrintToChat(client, "\x04[Editor]\x01 Mode: \x05Scale\x01"); } } else if(StrEqual(arg1, "edite") || (arg1[0] == 'c' && arg1[1] == 'u')) { int index = GetLookingEntity(client, Filter_ValidHats); //GetClientAimTarget(client, false); if(index > 0) { - WallBuilder[client].Import(index, false, MOVE_ORIGIN); + Editor[client].Import(index, false, MOVE_ORIGIN); char classname[32]; char targetname[32]; GetEntityClassname(index, classname, sizeof(classname)); @@ -669,20 +721,20 @@ public Action Command_ManageWalls(int client, int args) { ReplyToCommand(client, "\x04[Editor]\x01 Invalid or non existent entity"); } } else if(StrEqual(arg1, "copy")) { - if(WallBuilder[client].IsActive()) { - int oldEntity = WallBuilder[client].entity; + if(Editor[client].IsActive()) { + int oldEntity = Editor[client].entity; if(oldEntity == INVALID_ENT_REFERENCE) { PrintToChat(client, "\x04[Editor]\x01 Finish editing your wall first: \x05/wall done\x01 or \x04/wall cancel\x01"); } else { - int entity = WallBuilder[client].Copy(); + int entity = Editor[client].Copy(); PrintToChat(client, "\x04[Editor]\x01 Editing copy \x05%d\x01 of entity \x05%d\x01. End with \x05/edit done\x01 or \x04/edit cancel\x01", entity, oldEntity); } } else { int id = GetWallId(client, arg2); if(id > -1) { int entity = GetWallEntity(id); - WallBuilder[client].Import(entity, true); - GetCursorLimited(client, 100.0, WallBuilder[client].origin, Filter_IgnorePlayer); + Editor[client].Import(entity, true); + GetCursorLimited(client, 100.0, Editor[client].origin, Filter_IgnorePlayer); PrintToChat(client, "\x04[Editor]\x01 Editing copy of wall \x05%d\x01. End with \x05/wall build\x01 or \x04/wall cancel\x01", id); PrintToChat(client, "\x04[Editor]\x01 Mode: \x05Scale\x01"); } @@ -756,7 +808,7 @@ void GlowWall(int id, int glowColor[4], float lifetime = 5.0) { } void DeleteWall(int id) { - GlowWall(id, GLOW_RED); + GlowWall(id, GLOW_RED_ALPHA); int ref = GetWallEntity(id); if(IsValidEntity(ref)) { RemoveEntity(ref); diff --git a/scripting/include/hats/hats.sp b/scripting/include/hats/hats.sp index f292707..1b34f41 100644 --- a/scripting/include/hats/hats.sp +++ b/scripting/include/hats/hats.sp @@ -326,9 +326,9 @@ Action Command_DoAHat(int client, int args) { } } else if(arg[0] == 'd') { // Use the new wall editor - WallBuilder[client].Reset(); - WallBuilder[client].entity = EntIndexToEntRef(entity); - WallBuilder[client].SetMode(MOVE_ORIGIN); + Editor[client].Reset(); + Editor[client].entity = EntIndexToEntRef(entity); + Editor[client].SetMode(MOVE_ORIGIN); PrintToChat(client, "\x04[Hats] \x01Beta Prop Mover active for \x04%d", entity); } else { PrintToChat(client, "[Hats] Restored hat to its original position."); @@ -349,7 +349,7 @@ Action Command_DoAHat(int client, int args) { if(entity <= 0) { PrintCenterText(client, "[Hats] No entity found"); return Plugin_Handled; - } else if(entity == EntRefToEntIndex(WallBuilder[client].entity)) { + } else if(entity == EntRefToEntIndex(Editor[client].entity)) { // Prevent making an entity you editing a hat return Plugin_Handled; } else if(!isForced && cvar_sm_hats_max_distance.FloatValue > 0.0 && entity >= MaxClients) { @@ -382,7 +382,7 @@ Action Command_DoAHat(int client, int args) { } else if(GetClientTeam(entity) != 2 && ~cvar_sm_hats_flags.IntValue & view_as(HatConfig_InfectedHats)) { PrintToChat(client, "[Hats] Cannot make enemy a hat... it's dangerous"); return Plugin_Handled; - } else if(entity == EntRefToEntIndex(WallBuilder[client].entity)) { + } else if(entity == EntRefToEntIndex(Editor[client].entity)) { // Old check left in in case you hatting child entity PrintToChat(client, "[Hats] You are currently editing this entity"); return Plugin_Handled; @@ -569,7 +569,7 @@ void ClearHat(int i, bool restore = false) { // if(HasEntProp(entity, Prop_Send, "m_flModelScale")) // SetEntPropFloat(entity, Prop_Send, "m_flModelScale", 1.0); SetEntProp(modifyEntity, Prop_Send, "m_CollisionGroup", hatData[i].collisionGroup); - SetEntProp(modifyEntity, Prop_Send, "m_nSolidType", hatData[i].solidType); + // SetEntProp(modifyEntity, Prop_Send, "m_nSolidType", hatData[i].solidType); SetEntProp(modifyEntity, Prop_Send, "movetype", hatData[i].moveType); hatData[i].entity = INVALID_ENT_REFERENCE; @@ -667,7 +667,7 @@ bool CanHatBePlaced(int client, const float pos[3]) { int spawnFlags = L4D_GetNavArea_SpawnAttributes(nav) ; if(spawnFlags & NAV_SPAWN_CHECKPOINT) { PrintToServer("\"%L\" tried to place hat in saferoom, denied.", client); - PrintToChat(client, "[Hats] Hats are not allowed in saferoom and has been returned."); + PrintToChat(client, "[Hats] Hat is not allowed in saferoom and has been returned."); return false; } } @@ -834,7 +834,7 @@ void EquipHat(int client, int entity, const char[] classname = "", int flags = H L4D2_SetEntityGlow(modifyEntity, L4D2Glow_Constant, 0, 0, color, false); #endif - SetEntProp(modifyEntity, Prop_Send, "m_nSolidType", 0); + // SetEntProp(modifyEntity, Prop_Send, "m_nSolidType", 0); SetEntProp(modifyEntity, Prop_Send, "m_CollisionGroup", 1); SetEntProp(modifyEntity, Prop_Send, "movetype", MOVETYPE_NONE); } diff --git a/scripting/include/hats/props.sp b/scripting/include/hats/props.sp deleted file mode 100644 index 33a9e90..0000000 --- a/scripting/include/hats/props.sp +++ /dev/null @@ -1,644 +0,0 @@ -TopMenuObject g_propSpawnerCategory; -public void OnAdminMenuReady(Handle topMenuHandle) { - TopMenu topMenu = TopMenu.FromHandle(topMenuHandle); - if(topMenu != g_topMenu) { - g_propSpawnerCategory = topMenu.AddCategory("hats_editor", Category_Handler); - if(g_propSpawnerCategory != INVALID_TOPMENUOBJECT) { - topMenu.AddItem("editor_spawn", AdminMenu_Spawn, g_propSpawnerCategory, "sm_prop"); - topMenu.AddItem("editor_edit", AdminMenu_Edit, g_propSpawnerCategory, "sm_prop"); - topMenu.AddItem("editor_delete", AdminMenu_Delete, g_propSpawnerCategory, "sm_prop"); - topMenu.AddItem("editor_saveload", AdminMenu_SaveLoad, g_propSpawnerCategory, "sm_prop"); - } - } - g_topMenu = topMenu; -} - - -enum struct CategoryData { - char name[64]; - bool hasItems; - ArrayList items; -} -enum struct ItemData { - char model[128]; - char name[64]; -} -enum struct SaveData { - char model[128]; - buildType type; - float origin[3]; - float angles[3]; - int color[4]; - - void FromEntity(int entity) { - // Use this.model as a buffer: - GetEntityClassname(entity, this.model, sizeof(this.model)); - if(StrEqual(this.model, "prop_physics")) this.type = Build_Physics; - else if(StrEqual(this.model, "prop_dynamic")) { - if(GetEntProp(entity, Prop_Send, "m_nSolidType") == 0) { - this.type = Build_NonSolid; - } else { - this.type = Build_Solid; - } - } - - GetEntPropString(entity, Prop_Data, "m_ModelName", this.model, sizeof(this.model)); - GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin); - GetEntPropVector(entity, Prop_Send, "m_angRotation", this.angles); - GetEntityRenderColor(entity, this.color[0],this.color[1],this.color[2],this.color[3]); - } - - void Serialize(char[] output, int maxlen) { - Format( - output, maxlen, "%s,%d,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%d,%d,%d,%d", - this.model, this.type, this.origin[0], this.origin[1], this.origin[2], - this.angles[0], this.angles[1], this.angles[2], - this.color[0], this.color[1], this.color[2], this.color[3] - ); - } - - void Deserialize(const char[] output) { - char buffer[32]; - int index = SplitString(output, ",", this.model, sizeof(this.model)); - index = SplitString(output[index], ",", buffer, sizeof(buffer)); - this.type = view_as(StringToInt(buffer)); - for(int i = 0; i < 3; i++) { - index = SplitString(output[index], ",", buffer, sizeof(buffer)); - this.origin[i] = StringToFloat(buffer); - } - for(int i = 0; i < 3; i++) { - index = SplitString(output[index], ",", buffer, sizeof(buffer)); - this.angles[i] = StringToFloat(buffer); - } - for(int i = 0; i < 4; i++) { - index = SplitString(output[index], ",", buffer, sizeof(buffer)); - this.color[i] = StringToInt(buffer); - } - } - -} -ArrayList g_categories; -ArrayList g_spawnedItems; -ArrayList g_savedItems; - -bool LoadSaves(ArrayList saves) { - saves = new ArrayList(ByteCountToCells(64)); - char path[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/saves/%s", g_currentMap); - FileType fileType; - DirectoryListing listing = OpenDirectory(path); - if(listing == null) return false; - char buffer[64]; - while(listing.GetNext(buffer, sizeof(buffer), fileType)) { - saves.PushString(buffer); - } - delete listing; - return true; -} - -public bool LoadSave(const char[] save) { - char path[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/saves/%s/%s", g_currentMap, save); - // ArrayList savedItems = new ArrayList(sizeof(SaveData)); - File file = OpenFile(path, "r"); - if(file == null) return false; - char buffer[256]; - SaveData data; - while(file.ReadLine(buffer, sizeof(buffer))) { - data.Deserialize(buffer); - int entity = -1; - if(data.type == Build_Physics) - entity = CreateEntityByName("prop_physics"); - else - entity = CreateEntityByName("prop_dynamic"); - if(entity == -1) continue; - PrecacheModel(data.model); - DispatchKeyValue(entity, "model", data.model); - DispatchKeyValue(entity, "targetname", "saved_prop"); - DispatchKeyValue(entity, "solid", data.type == Build_NonSolid ? "0" : "6"); - TeleportEntity(entity, data.origin, data.angles, NULL_VECTOR); - if(!DispatchSpawn(entity)) continue; - // TODO: Setrendertype? - SetEntityRenderColor(entity, data.color[0], data.color[1], data.color[2], data.color[3]); - // TODO: previews? - // g_savedItems.PushArray(data); - } - delete file; - // delete savedItems; - return true; -} - -bool CreateSave(const char[] name) { - char path[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/saves/%s/%s.txt", g_currentMap, name); - File file = OpenFile(name, "w"); - if(file == null) return false; - char buffer[132]; - SaveData data; - for(int i = 0; i < g_spawnedItems.Length; i++) { - int ref = g_spawnedItems.Get(i); - data.FromEntity(ref); - data.Serialize(buffer, sizeof(buffer)); - file.WriteLine("%s", buffer); - } - file.Flush(); - delete file; - return true; -} - -void UnloadSave() { - if(g_savedItems != null) { - delete g_savedItems; - } -} - -public void LoadCategories() { - if(g_categories != null) return; - g_categories = new ArrayList(sizeof(CategoryData)); - char path[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/models"); - LoadFolder(g_categories, path); -} -public void UnloadCategories() { - if(g_categories == null) return; - _UnloadCategories(g_categories); - delete g_categories; -} -void _UnloadCategories(ArrayList list) { - CategoryData cat; - for(int i = 0; i < list.Length; i++) { - list.GetArray(i, cat); - _UnloadCategory(cat); - } -} -void _UnloadCategory(CategoryData cat) { - // Is a sub-category: - if(!cat.hasItems) { - _UnloadCategories(cat.items); - } - delete cat.items; -} - -void LoadFolder(ArrayList parent, const char[] rootPath) { - char buffer[PLATFORM_MAX_PATH]; - FileType fileType; - DirectoryListing listing = OpenDirectory(rootPath); - if(listing == null) { - LogError("Cannot open \"%s\"", rootPath); - } - while(listing.GetNext(buffer, sizeof(buffer), fileType)) { - if(fileType == FileType_Directory) { - // TODO: support subcategory - if(buffer[0] == '.') continue; - CategoryData data; - Format(data.name, sizeof(data.name), "%s>>", buffer); - data.items = new ArrayList(); - - Format(buffer, sizeof(buffer), "%s/%s", rootPath, buffer); - LoadFolder(data.items, buffer); - parent.PushArray(data); - } else if(fileType == FileType_File) { - Format(buffer, sizeof(buffer), "%s/%s", rootPath, buffer); - LoadProps(parent, buffer); - } - } - delete listing; -} - -void LoadProps(ArrayList parent, const char[] filePath) { - File file = OpenFile(filePath, "r"); - if(file == null) { - PrintToServer("[Props] Cannot open file \"%s\"", filePath); - return; - } - CategoryData category; - category.items = new ArrayList(sizeof(ItemData)); - category.hasItems = true; - char buffer[128]; - if(!file.ReadLine(buffer, sizeof(buffer))) { - delete file; - return; - } - ReplaceString(buffer, sizeof(buffer), "\n", ""); - ReplaceString(buffer, sizeof(buffer), "\r", ""); - Format(category.name, sizeof(category.name), "%s>", buffer); - while(file.ReadLine(buffer, sizeof(buffer))) { - ItemData item; - int index = SplitString(buffer, " ", item.model, sizeof(item.model)); - if(index == -1) { - strcopy(item.name, sizeof(item.name), buffer); - } else { - strcopy(item.name, sizeof(item.name), buffer[index]); - } - category.items.PushArray(item); - } - parent.PushArray(category); - delete file; -} -public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) { - if(!g_isSearchActive[client]) { - return Plugin_Continue; - } - ArrayList results = SearchItems(sArgs); - if(results.Length == 0) { - CPrintToChat(client, "\x04[Editor]\x01 No results found. :("); - } else { - ShowItemMenuAny(client, results); - } - delete results; - return Plugin_Handled; -} -#define MAX_SEARCH_RESULTS 30 -ArrayList SearchItems(const char[] query) { - // TODO: search - ArrayList results = new ArrayList(sizeof(ItemData)); - _searchCategory(results, g_categories, query); - return results; -} - -void _searchCategory(ArrayList results, ArrayList categories, const char[] query) { - CategoryData cat; - for(int i = 0; i < categories.Length; i++) { - categories.GetArray(i, cat); - if(cat.hasItems) { - _searchItems(results, cat.items, query); - } else { - _searchCategory(results, cat.items, query); - } - if(results.Length > MAX_SEARCH_RESULTS) return; - } -} -void _searchItems(ArrayList results, ArrayList items, const char[] query) { - ItemData item; - for(int i = 0; i < items.Length; i++) { - items.GetArray(i, item); - if(StrContains(item.name, query, false)) { - results.PushArray(item); - } - if(results.Length > MAX_SEARCH_RESULTS) return; - } -} - -void Category_Handler(TopMenu topmenu, TopMenuAction action, TopMenuObject topobj_id, int param, char[] buffer, int maxlength) { - if(action == TopMenuAction_DisplayTitle) { - Format(buffer, maxlength, "Select a task:"); - } else if(action == TopMenuAction_DisplayOption) { - Format(buffer, maxlength, "Spawn Props (Beta)"); - } -} - -void AdminMenu_Spawn(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) { - if(action == TopMenuAction_DisplayOption) { - Format(buffer, maxlength, "Spawn Props"); - } else if(action == TopMenuAction_SelectOption) { - if(!FindConVar("sm_cheats").BoolValue) { - CReplyToCommand(param, "\x04[Editor] \x01Set \x05sm_cheats\x01 to \x051\x01 to use the prop spawner"); - return; - } - Menu menu = new Menu(Spawn_RootHandler); - menu.SetTitle("Choose list:"); - menu.AddItem("f", "Favorites"); - menu.AddItem("r", "Recents"); - menu.AddItem("s", "Search"); - menu.AddItem("n", "Prop List"); - menu.ExitBackButton = true; - menu.ExitButton = true; - menu.Display(param, MENU_TIME_FOREVER); - } -} - -int Spawn_RootHandler(Menu menu, MenuAction action, int client, int param2) { - if (action == MenuAction_Select) { - char info[2]; - menu.GetItem(param2, info, sizeof(info)); - switch(info[0]) { - case 'f': Spawn_ShowFavorites(client); - case 'r': Spawn_ShowRecents(client); - case 's': Spawn_ShowSearch(client); - case 'n': ShowCategoryList(client); - } - // TODO: handle back (to top menu) - } else if (action == MenuAction_End) - delete menu; - return 0; -} -Spawn_ShowFavorites(int client) { - PrintToChat(client, "In development"); - return; - // Menu menu = new Menu(SpawnItemHandler); - // char model[128]; - // for(int i = 0; i <= g_spawnedItems.Length; i++) { - // int ref = g_spawnedItems.Get(i); - // if(IsValidEntity(ref)) { - // GetEntPropString(ref, Prop_Data, "m_ModelName", model, sizeof(model)); - // menu.AddItem(model, model); - // } - // } - // menu.ExitBackButton = true; - // menu.ExitButton = true; - // menu.Display(client, MENU_TIME_FOREVER); -} -Spawn_ShowRecents(int client) { - Menu menu = new Menu(SpawnItemHandler); - menu.SetTitle("Recent Props:"); - char model[128]; - for(int i = 0; i <= g_spawnedItems.Length; i++) { - int ref = g_spawnedItems.Get(i); - if(IsValidEntity(ref)) { - GetEntPropString(ref, Prop_Data, "m_ModelName", model, sizeof(model)); - menu.AddItem(model, model); - } - } - menu.ExitBackButton = true; - menu.ExitButton = true; - menu.Display(client, MENU_TIME_FOREVER); -} -Spawn_ShowSearch(int client) { - g_isSearchActive[client] = true; - CReplyToCommand(client, "\x04[Editor] \x01Please enter search query in chat:"); -} -void AdminMenu_Edit(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) { - if(action == TopMenuAction_DisplayOption) { - Format(buffer, maxlength, "Edit Props"); - } else if(action == TopMenuAction_SelectOption) { - ShowEditList(param); - } -} -void ShowDeleteList(int client, int index) { - Menu menu = new Menu(DeleteHandler); - menu.SetTitle("Delete Props"); - - menu.AddItem("-1", "Delete All"); - menu.AddItem("-2", "Delete All (Mine Only)"); - char info[8]; - char buffer[128]; - for(int i = 0; i < g_spawnedItems.Length; i++) { - int ref = g_spawnedItems.Get(i); - IntToString(i, info, sizeof(info)); - GetEntPropString(ref, Prop_Data, "m_ModelName", buffer, sizeof(buffer)); - index = FindCharInString(buffer, '/', true); - if(index != -1) - menu.AddItem(info, buffer[index + 1]); - } - - menu.ExitBackButton = true; - menu.ExitButton = true; - // Add +2 to the index for the two "Delete ..." buttons - menu.DisplayAt(client, index + 2, MENU_TIME_FOREVER); -} -void ShowEditList(int client, int index = 0) { - Menu menu = new Menu(EditHandler); - menu.SetTitle("Edit Prop"); - - char info[8]; - char buffer[32]; - for(int i = 0; i < g_spawnedItems.Length; i++) { - int ref = g_spawnedItems.Get(i); - IntToString(i, info, sizeof(info)); - GetEntPropString(ref, Prop_Data, "m_ModelName", buffer, sizeof(buffer)); - index = FindCharInString(buffer, '/', true); - if(index != -1) - menu.AddItem(info, buffer[index + 1]); - } - - menu.ExitBackButton = true; - menu.ExitButton = true; - // Add +2 to the index for the two "Delete ..." buttons - menu.DisplayAt(client, index, MENU_TIME_FOREVER); -} - -void AdminMenu_Delete(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) { - if(action == TopMenuAction_DisplayOption) { - Format(buffer, maxlength, "Delete Props"); - } else if(action == TopMenuAction_SelectOption) { - ShowDeleteList(param, -2); - } -} - -void AdminMenu_SaveLoad(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) { - if(action == TopMenuAction_DisplayOption) { - Format(buffer, maxlength, "Save / Load"); - } else if(action == TopMenuAction_SelectOption) { - - ArrayList saves; - LoadSaves(saves); - Menu menu = new Menu(SaveLoadHandler); - menu.SetTitle("Save / Load"); - char name[64]; - menu.AddItem("", "[New Save]"); - for(int i = 0; i < saves.Length; i++) { - saves.GetString(i, name, sizeof(name)); - menu.AddItem(name, name); - } - menu.ExitBackButton = true; - menu.ExitButton = true; - menu.Display(param, MENU_TIME_FOREVER); - delete saves; - } -} - -void ShowCategoryList(int client) { - LoadCategories(); - Menu menu = new Menu(SpawnCategoryHandler); - menu.SetTitle("Choose a category"); - CategoryData cat; - char info[4]; - for(int i = 0; i < g_categories.Length; i++) { - g_categories.GetArray(i, cat); - Format(info, sizeof(info), "%d", i); - // TODO: add support for nested - if(cat.hasItems) - menu.AddItem(info, cat.name); - } - menu.ExitBackButton = true; - menu.ExitButton = true; - menu.DisplayAt(client, g_lastCategoryIndex[client], MENU_TIME_FOREVER); -} - -int SpawnCategoryHandler(Menu menu, MenuAction action, int client, int param2) { - if (action == MenuAction_Select) { - char info[8]; - menu.GetItem(param2, info, sizeof(info)); - int index = StringToInt(info); - if(index > 0) { - ShowItemMenu(client, index); - } - } else if (action == MenuAction_End) - delete menu; - return 0; -} - -int SaveLoadHandler(Menu menu, MenuAction action, int client, int param2) { - if (action == MenuAction_Select) { - char saveName[64]; - menu.GetItem(param2, saveName, sizeof(saveName)); - if(saveName[0] == '\0') { - // Save new - FormatTime(saveName, sizeof(saveName), "%Y-%m-%d %X"); - if(CreateSave(saveName)) { - PrintToChat(client, "\x04[Editor]\x01 Created save \x05%s.txt", saveName); - } else { - PrintToChat(client, "\x04[Editor]\x01 Error creating save file"); - } - } else if(LoadSave(saveName)) { - PrintToChat(client, "\x04[Editor]\x01 Loaded save \x05%s", saveName); - } else { - PrintToChat(client, "\x04[Editor]\x01 Error loading save file"); - } - } else if (action == MenuAction_Cancel) { - if(param2 == MenuCancel_ExitBack) { - DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client); - } - } else if (action == MenuAction_End) - delete menu; - return 0; -} - -int DeleteHandler(Menu menu, MenuAction action, int client, int param2) { - if (action == MenuAction_Select) { - char info[8]; - menu.GetItem(param2, info, sizeof(info)); - int index = StringToInt(info); - if(index == -1) { - // Delete all (everyone) - int count = DeleteAll(); - PrintToChat(client, "\x04[Editor]\x01 Deleted \x05%d\x01 items", count); - ShowDeleteList(client, index); - } else if(index == -2) { - // Delete all (mine only) - int count = DeleteAll(client); - PrintToChat(client, "\x04[Editor]\x01 Deleted \x05%d\x01 items", count); - ShowDeleteList(client, index); - } else { - int ref = g_spawnedItems.Get(index); - // TODO: add delete confirm - if(IsValidEntity(ref)) { - RemoveEntity(ref); - } - g_spawnedItems.Erase(index); - if(index > 0) { - index--; - } - ShowDeleteList(client, index); - } - } else if (action == MenuAction_Cancel) { - if(param2 == MenuCancel_ExitBack) { - DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client); - } - } else if (action == MenuAction_End) - delete menu; - return 0; -} - -void - -int DeleteAll(int onlyPlayer = 0) { - int userid = onlyPlayer > 0 ? GetClientUserId(onlyPlayer) : 0; - int count; - for(int i = 0; i < g_spawnedItems.Length; i++) { - int ref = g_spawnedItems.Get(i); - int spawnedBy = g_spawnedItems.Get(i, 1); - // Skip if wishing to only delete certain items: - if(onlyPlayer != 0 && spawnedBy != userid) continue; - if(IsValidEntity(ref)) { - RemoveEntity(ref); - } - g_spawnedItems.Erase(i); - count++; - } - return count; -} - -int EditHandler(Menu menu, MenuAction action, int client, int param2) { - if (action == MenuAction_Select) { - char info[8]; - menu.GetItem(param2, info, sizeof(info)); - int index = StringToInt(info); - int ref = g_spawnedItems.Get(index); - int entity = EntRefToEntIndex(ref); - if(entity > 0) { - WallBuilder[client].Import(entity, false); - PrintToChat(client, "\x04[Editor]\x01 Editing entity \x05%d", entity); - } else { - PrintToChat(client, "\x04[Editor]\x01 Entity disappeared."); - g_spawnedItems.Erase(index); - index--; - } - ShowEditList(client, index); - } else if (action == MenuAction_Cancel) { - if(param2 == MenuCancel_ExitBack) { - DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client); - } - } else if (action == MenuAction_End) - delete menu; - return 0; -} - - -void ShowItemMenuAny(int client, ArrayList items, const char[] title = "") { - Menu itemMenu = new Menu(SpawnItemHandler); - if(title[0] != '\0') - itemMenu.SetTitle(title); - ItemData item; - char info[132]; - for(int i = 0; i < items.Length; i++) { - items.GetArray(i, item); - Format(info, sizeof(info), "%d|%s", i, item.model); - itemMenu.AddItem(info, item.name); - } - itemMenu.ExitBackButton = true; - itemMenu.ExitButton = true; - itemMenu.DisplayAt(client, g_lastItemIndex[client], MENU_TIME_FOREVER); -} - -void ShowItemMenu(int client, int index) { - if(g_lastCategoryIndex[client] != index) { - g_lastCategoryIndex[client] = index; - g_lastItemIndex[client] = 0; //Reset - } - CategoryData category; - g_categories.GetArray(index, category); - ShowItemMenuAny(client, category.items, category.name); -} - -int SpawnItemHandler(Menu menu, MenuAction action, int client, int param2) { - if (action == MenuAction_Select) { - char info[132]; - menu.GetItem(param2, info, sizeof(info)); - char index[4]; - int modelIndex = SplitString(info, "|", index, sizeof(index)); - g_lastItemIndex[client] = StringToInt(index); - - if(WallBuilder[client].PreviewModel(info[modelIndex])) { - PrintToChat(client, "\x04[Editor]\x01 Spawning: \x04%s\x01", info[modelIndex+7]); - ShowHint(client); - } else { - PrintToChat(client, "\x04[Editor]\x01 Error spawning model \x01(%s)"); - } - - ShowItemMenu(client, g_lastCategoryIndex[client]); - } else if(action == MenuAction_Cancel) { - if(param2 == MenuCancel_ExitBack) { - ShowCategoryList(client); - } - } else if (action == MenuAction_End) { - delete menu; - } - return 0; -} - -#define SHOW_HINT_MIN_DURATION 600 // 600 s (10min) -void ShowHint(int client) { - int time = GetTime(); - if(time - g_lastShowedHint[client] < SHOW_HINT_MIN_DURATION) return; - PrintToChat(client, "\x05R: \x01Change Mode"); - PrintToChat(client, "\x05Middle Click: \x01Cancel Placement \x05Shift + Middle Click: \x01Place \x05Ctrl + Middle Click: \x01Change Type"); - PrintToChat(client, "\x05E: \x01Rotate (hold, use mouse) \x05Left Click: \x01Rotate Axis \x05Right Click: \x01Snap Angle"); - - g_lastShowedHint[client] = time; -} - -Action Command_Props(int client, int args) { - PrintToChat(client, "\x05Not implemented"); - return Plugin_Handled; -} \ No newline at end of file diff --git a/scripting/include/hats/props/base.sp b/scripting/include/hats/props/base.sp new file mode 100644 index 0000000..c63aa7f --- /dev/null +++ b/scripting/include/hats/props/base.sp @@ -0,0 +1,145 @@ +char g_pendingSaveName[64]; +int g_pendingSaveClient; + +/* Wish to preface this file: +* It's kinda messy. The main structs are: +* - ItemData +* - CategoryData + +The rest are kinda necessary, for sorting reasons (SearchData, RecentEntry). + +*/ +enum struct PlayerPropData { + ArrayList listBuffer; + bool clearListBuffer; + int lastCategoryIndex; + int lastItemIndex; + int lastShowedHint; + char classnameOverride[32]; + + bool isSearchActive; + ArrayList markedProps; + + // Called on PlayerDisconnect + void Reset() { + if(this.listBuffer != null) delete this.listBuffer; + if(this.markedProps != null) delete this.markedProps; + this.isSearchActive = false; + this.clearListBuffer = false; + this.lastCategoryIndex = 0; + this.lastItemIndex = 0; + this.lastShowedHint = 0; + this.classnameOverride[0] = '\0'; + } + + // Sets the list buffer + void SetList(ArrayList list, bool cleanupAfterUse = false) { + this.listBuffer = list; + this.clearListBuffer = cleanupAfterUse; + } + + // Is currently only called on item handler cancel (to clear search/recents buffer) + void CleanupBuffer() { + if(this.listBuffer != null && this.clearListBuffer) { + delete this.listBuffer; + this.clearListBuffer = false; + } + } +} +PlayerPropData g_PropData[MAXPLAYERS+1]; + +enum struct CategoryData { + // The display name of category + char name[64]; + // If set, overwrites the classname it is spawned as + char classnameOverride[32]; + bool hasItems; // true: items is ArrayList, false: items is ArrayList + ArrayList items; +} +enum struct ItemData { + char model[128]; + char name[64]; + + void FromSearchData(SearchData search) { + strcopy(this.model, sizeof(this.model), search.model); + strcopy(this.name, sizeof(this.name), search.name); + } +} +enum struct SearchData { + char model[128]; + char name[64]; + int index; + + void FromItemData(ItemData item) { + strcopy(this.model, sizeof(this.model), item.model); + strcopy(this.name, sizeof(this.name), item.name); + } +} +enum struct SaveData { + char model[128]; + buildType type; + float origin[3]; + float angles[3]; + int color[4]; + + void FromEntity(int entity) { + // Use this.model as a buffer: + GetEntityClassname(entity, this.model, sizeof(this.model)); + if(StrEqual(this.model, "prop_physics")) this.type = Build_Physics; + else if(StrEqual(this.model, "prop_dynamic")) { + if(GetEntProp(entity, Prop_Send, "m_nSolidType") == 0) { + this.type = Build_NonSolid; + } else { + this.type = Build_Solid; + } + } + + GetEntPropString(entity, Prop_Data, "m_ModelName", this.model, sizeof(this.model)); + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin); + GetEntPropVector(entity, Prop_Send, "m_angRotation", this.angles); + GetEntityRenderColor(entity, this.color[0],this.color[1],this.color[2],this.color[3]); + } + + void Serialize(char[] output, int maxlen) { + Format( + output, maxlen, "%s,%d,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%d,%d,%d,%d", + this.model, this.type, this.origin[0], this.origin[1], this.origin[2], + this.angles[0], this.angles[1], this.angles[2], + this.color[0], this.color[1], this.color[2], this.color[3] + ); + } + + void Deserialize(const char[] input) { + char buffer[16]; + int index = SplitString(input, ",", this.model, sizeof(this.model)); + index += SplitString(input[index], ",", buffer, sizeof(buffer)); + this.type = view_as(StringToInt(buffer)); + for(int i = 0; i < 3; i++) { + index += SplitString(input[index], ",", buffer, sizeof(buffer)); + this.origin[i] = StringToFloat(buffer); + } + for(int i = 0; i < 3; i++) { + index += SplitString(input[index], ",", buffer, sizeof(buffer)); + this.angles[i] = StringToFloat(buffer); + } + for(int i = 0; i < 4; i++) { + index += SplitString(input[index], ",", buffer, sizeof(buffer)); + this.color[i] = StringToInt(buffer); + } + } +} + +enum struct RecentEntry { + char name[64]; + int count; +} + +ArrayList g_categories; // ArrayList +ArrayList g_spawnedItems; // ArrayList(block=2) +ArrayList g_savedItems; // ArrayList +StringMap g_recentItems; // Key: model[128], value: RecentEntry + +#include +#include +#include +#include \ No newline at end of file diff --git a/scripting/include/hats/props/cmd.sp b/scripting/include/hats/props/cmd.sp new file mode 100644 index 0000000..2504f0a --- /dev/null +++ b/scripting/include/hats/props/cmd.sp @@ -0,0 +1,63 @@ +Action Command_Props(int client, int args) { + char arg[32]; + GetCmdArg(1, arg, sizeof(arg)); + if(args == 0 || StrEqual(arg, "help")) { + PrintToChat(client, "See console for available sub-commands"); + PrintToConsole(client, "help - this"); + PrintToConsole(client, "search "); + PrintToConsole(client, "edit "); + PrintToConsole(client, "del "); + PrintToConsole(client, "add "); + PrintToConsole(client, "controls - list all the controls"); + } else if(StrEqual(arg, "search")) { + if(args == 1) { + PrintToChat(client, "\x04[Editor]\x01 Enter your search query:"); + g_PropData[client].isSearchActive = true; + } else { + char query[32]; + GetCmdArg(2, query, sizeof(query)); + DoSearch(client, query); + } + } else if(StrEqual(arg, "edit")) { + char arg2[32]; + GetCmdArg(2, arg2, sizeof(arg2)); + int index; + if(StrEqual(arg2, "last")) { + // Get last one + index = GetSpawnedIndex(client, -1); + } else { + index = StringToInt(arg2); + } + if(index >= 0 && index < g_spawnedItems.Length) { + int entity = EntRefToEntIndex(g_spawnedItems.Get(index)); + Editor[client].Import(entity); + PrintToChat(client, "\x04[Editor]\x01 Editing entity \x05%d", entity); + } else { + PrintToChat(client, "\x04[Editor]\x01 Invalid index, out of bounds. Enter a value between [0, %d]", g_spawnedItems.Length - 1); + } + } else if(StrEqual(arg, "del")) { + char arg2[32]; + GetCmdArg(2, arg2, sizeof(arg2)); + int index; + if(StrEqual(arg2, "last")) { + // Get last one + index = GetSpawnedIndex(client, -1); + } else { + index = StringToInt(arg2); + } + + if(index >= 0 && index < g_spawnedItems.Length) { + int entity = EntRefToEntIndex(g_spawnedItems.Get(index)); + if(entity > 0 && IsValidEntity(entity)) { + RemoveEntity(entity); + } + g_spawnedItems.Erase(index); + PrintToChat(client, "\x04[Editor]\x01 Deleted entity \x05%d", entity); + } else { + PrintToChat(client, "\x04[Editor]\x01 Invalid index, out of bounds. Enter a value between [0, %d]", g_spawnedItems.Length - 1); + } + }else { + PrintToChat(client, "\x05Not implemented"); + } + return Plugin_Handled; +} \ No newline at end of file diff --git a/scripting/include/hats/props/menu_handlers.sp b/scripting/include/hats/props/menu_handlers.sp new file mode 100644 index 0000000..fc0e3b9 --- /dev/null +++ b/scripting/include/hats/props/menu_handlers.sp @@ -0,0 +1,239 @@ +TopMenuObject g_propSpawnerCategory; +public void OnAdminMenuReady(Handle topMenuHandle) { + TopMenu topMenu = TopMenu.FromHandle(topMenuHandle); + if(g_topMenu != topMenuHandle) { + g_propSpawnerCategory = topMenu.AddCategory("hats_editor", Category_Handler); + if(g_propSpawnerCategory != INVALID_TOPMENUOBJECT) { + topMenu.AddItem("editor_spawn", AdminMenu_Spawn, g_propSpawnerCategory, "sm_prop"); + topMenu.AddItem("editor_edit", AdminMenu_Edit, g_propSpawnerCategory, "sm_prop"); + topMenu.AddItem("editor_delete", AdminMenu_Delete, g_propSpawnerCategory, "sm_prop"); + topMenu.AddItem("editor_saveload", AdminMenu_SaveLoad, g_propSpawnerCategory, "sm_prop"); + } + g_topMenu = topMenu; + } +} + +///////////// +// HANDLERS +///////////// +void Category_Handler(TopMenu topmenu, TopMenuAction action, TopMenuObject topobj_id, int param, char[] buffer, int maxlength) { + if(action == TopMenuAction_DisplayTitle) { + Format(buffer, maxlength, "Select a task:"); + } else if(action == TopMenuAction_DisplayOption) { + Format(buffer, maxlength, "Spawn Props (Beta)"); + } +} + +void AdminMenu_Spawn(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) { + if(action == TopMenuAction_DisplayOption) { + Format(buffer, maxlength, "Spawn Props"); + } else if(action == TopMenuAction_SelectOption) { + ConVar cheats = FindConVar("sm_cheats"); + if(cheats != null && !cheats.BoolValue) { + CReplyToCommand(param, "\x04[Editor] \x01Set \x05sm_cheats\x01 to \x051\x01 to use the prop spawner"); + return; + } + ShowSpawnRoot(param); + } +} + +int Spawn_RootHandler(Menu menu, MenuAction action, int client, int param2) { + if (action == MenuAction_Select) { + char info[2]; + menu.GetItem(param2, info, sizeof(info)); + switch(info[0]) { + case 'f': Spawn_ShowFavorites(client); + case 'r': Spawn_ShowRecents(client); + case 's': Spawn_ShowSearch(client); + case 'n': ShowCategoryList(client); + } + // TODO: handle back (to top menu) + } else if (action == MenuAction_Cancel) { + if(param2 == MenuCancel_ExitBack) { + DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client); + } + } else if (action == MenuAction_End) + delete menu; + return 0; +} +void AdminMenu_Edit(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) { + if(action == TopMenuAction_DisplayOption) { + Format(buffer, maxlength, "Edit Props"); + } else if(action == TopMenuAction_SelectOption) { + ShowEditList(param); + } +} +void AdminMenu_Delete(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) { + if(action == TopMenuAction_DisplayOption) { + Format(buffer, maxlength, "Delete Props"); + } else if(action == TopMenuAction_SelectOption) { + ShowDeleteList(param); + } +} + +void AdminMenu_SaveLoad(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) { + if(action == TopMenuAction_DisplayOption) { + Format(buffer, maxlength, "Save / Load"); + } else if(action == TopMenuAction_SelectOption) { + Menu menu = new Menu(SaveLoadHandler); + menu.SetTitle("Save / Load"); + char name[64]; + menu.AddItem("", "[New Save]"); + ArrayList saves = LoadSaves(); + if(saves != null) { + for(int i = 0; i < saves.Length; i++) { + saves.GetString(i, name, sizeof(name)); + menu.AddItem(name, name); + } + delete saves; + } + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.Display(param, MENU_TIME_FOREVER); + } +} + +int SpawnCategoryHandler(Menu menu, MenuAction action, int client, int param2) { + if (action == MenuAction_Select) { + char info[8]; + menu.GetItem(param2, info, sizeof(info)); + int index = StringToInt(info); + PrintToServer("Item in category list selected: #%d", index); + // Use g_categories, but if this is nested, then when a nested is selected, we need to use that list + ShowItemMenu(client, index); + } else if (action == MenuAction_Cancel) { + if(param2 == MenuCancel_ExitBack) { + ShowSpawnRoot(client); + } + } else if (action == MenuAction_End) + delete menu; + return 0; +} + +int SaveLoadHandler(Menu menu, MenuAction action, int client, int param2) { + if (action == MenuAction_Select) { + char saveName[64]; + menu.GetItem(param2, saveName, sizeof(saveName)); + if(saveName[0] == '\0') { + // Save new + FormatTime(saveName, sizeof(saveName), "%Y-%m-%d_%H-%I-%M"); + if(CreateSave(saveName)) { + PrintToChat(client, "\x04[Editor]\x01 Saved as \x05%s/%s.txt", g_currentMap, saveName); + } else { + PrintToChat(client, "\x04[Editor]\x01 Error creating save file"); + } + } else if(LoadSave(saveName, true)) { + strcopy(g_pendingSaveName, sizeof(g_pendingSaveName), saveName); + g_pendingSaveClient = client; + PrintToChat(client, "\x04[Editor]\x01 Previewing save \x05%s", saveName); + PrintToChat(client, "\x04[Editor]\x01 Press \x05Shift + Middle Mouse\x01 to spawn, \x05Middle Mouse\x01 to cancel"); + } else { + PrintToChat(client, "\x04[Editor]\x01 Error loading save file"); + } + } else if (action == MenuAction_Cancel) { + if(param2 == MenuCancel_ExitBack) { + DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client); + } + } else if (action == MenuAction_End) + delete menu; + return 0; +} +int DeleteHandler(Menu menu, MenuAction action, int client, int param2) { + if (action == MenuAction_Select) { + char info[8]; + menu.GetItem(param2, info, sizeof(info)); + int index = StringToInt(info); + if(index == -1) { + // Delete all (everyone) + int count = DeleteAll(); + PrintToChat(client, "\x04[Editor]\x01 Deleted \x05%d\x01 items", count); + ShowDeleteList(client); + } else if(index == -2) { + // Delete all (mine only) + int count = DeleteAll(client); + PrintToChat(client, "\x04[Editor]\x01 Deleted \x05%d\x01 items", count); + ShowDeleteList(client); + } else if(index == -3) { + if(g_PropData[client].markedProps != null) { + EndDeleteTool(client, false); + } else { + g_PropData[client].markedProps = new ArrayList(); + PrintToChat(client, "\x04[Editor]\x01 Delete tool active. Press \x05E (Interact)\x01 to mark props."); + } + ShowDeleteList(client); + } else { + int ref = g_spawnedItems.Get(index); + // TODO: add delete confirm + if(IsValidEntity(ref)) { + RemoveEntity(ref); + } + g_spawnedItems.Erase(index); + if(index > 0) { + index--; + } + ShowDeleteList(client, index); + } + } else if (action == MenuAction_Cancel) { + if(param2 == MenuCancel_ExitBack) { + DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client); + } + } else if (action == MenuAction_End) + delete menu; + return 0; +} + +int SpawnItemHandler(Menu menu, MenuAction action, int client, int param2) { + if (action == MenuAction_Select) { + char info[132]; + menu.GetItem(param2, info, sizeof(info)); + char index[4]; + char model[128]; + int nameIndex = SplitString(info, "|", index, sizeof(index)); + nameIndex += SplitString(info[nameIndex], "|", model, sizeof(model)); + g_PropData[client].lastItemIndex = StringToInt(index); + if(Editor[client].PreviewModel(model, g_PropData[client].classnameOverride)) { + Editor[client].SetData(info[nameIndex]); + PrintHintText(client, "%s\n%s", info[nameIndex], model); + ShowHint(client); + } else { + PrintToChat(client, "\x04[Editor]\x01 Error spawning preview \x01(%s)", model); + } + + ShowItemMenuAny(client, null); // Use last menu + // ShowItemMenu(client, g_PropData[client].lastCategoryIndex); + } else if(action == MenuAction_Cancel) { + if(param2 == MenuCancel_ExitBack) { + ShowCategoryList(client, g_PropData[client].listBuffer); + } + g_PropData[client].CleanupBuffer(); + + } else if (action == MenuAction_End) { + delete menu; + } + return 0; +} + +int EditHandler(Menu menu, MenuAction action, int client, int param2) { + if (action == MenuAction_Select) { + char info[8]; + menu.GetItem(param2, info, sizeof(info)); + int index = StringToInt(info); + int ref = g_spawnedItems.Get(index); + int entity = EntRefToEntIndex(ref); + if(entity > 0) { + Editor[client].Import(entity, false); + PrintToChat(client, "\x04[Editor]\x01 Editing entity \x05%d", entity); + } else { + PrintToChat(client, "\x04[Editor]\x01 Entity disappeared."); + g_spawnedItems.Erase(index); + index--; + } + ShowEditList(client, index); + } else if (action == MenuAction_Cancel) { + if(param2 == MenuCancel_ExitBack) { + DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client); + } + } else if (action == MenuAction_End) + delete menu; + return 0; +} diff --git a/scripting/include/hats/props/menu_methods.sp b/scripting/include/hats/props/menu_methods.sp new file mode 100644 index 0000000..4b6bb50 --- /dev/null +++ b/scripting/include/hats/props/menu_methods.sp @@ -0,0 +1,174 @@ +///////////// +// METHODS +///////////// +void ShowSpawnRoot(int client) { + Menu menu = new Menu(Spawn_RootHandler); + menu.SetTitle("Choose list:"); + menu.AddItem("f", "Favorites (WIP)"); + menu.AddItem("r", "Recents"); + menu.AddItem("s", "Search"); + menu.AddItem("n", "Prop List"); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +void Spawn_ShowFavorites(int client) { + PrintToChat(client, "In development"); + return; + // Menu menu = new Menu(SpawnItemHandler); + // char model[128]; + // for(int i = 0; i <= g_spawnedItems.Length; i++) { + // int ref = g_spawnedItems.Get(i); + // if(IsValidEntity(ref)) { + // GetEntPropString(ref, Prop_Data, "m_ModelName", model, sizeof(model)); + // menu.AddItem(model, model); + // } + // } + // menu.ExitBackButton = true; + // menu.ExitButton = true; + // menu.Display(client, MENU_TIME_FOREVER); +} +void Spawn_ShowRecents(int client) { + CReplyToCommand(client, "\x04[Editor] \x01Disabled due to crash issues :D"); + return; + if(g_recentItems == null) LoadRecents(); + ArrayList items = GetRecentsItemList(); + if(items.Length == 0) { + CReplyToCommand(client, "\x04[Editor] \x01No recent props spawned."); + return; + } + ShowItemMenuAny(client, items, "Recents", true); +} +void Spawn_ShowSearch(int client) { + g_PropData[client].isSearchActive = true; + CReplyToCommand(client, "\x04[Editor] \x01Please enter search query in chat:"); +} +void ShowDeleteList(int client, int index = -3) { + Menu menu = new Menu(DeleteHandler); + menu.SetTitle("Delete Props"); + + menu.AddItem("-1", "Delete All"); + menu.AddItem("-2", "Delete All (Mine Only)"); + menu.AddItem("-3", "Delete Tool"); + // menu.AddItem("-4", "Delete Last Save"); + char info[8]; + char buffer[128]; + for(int i = 0; i < g_spawnedItems.Length; i++) { + int ref = GetSpawnedItem(i); + if(ref == -1) continue; + IntToString(i, info, sizeof(info)); + GetEntPropString(ref, Prop_Data, "m_ModelName", buffer, sizeof(buffer)); + index = FindCharInString(buffer, '/', true); + if(index != -1) + menu.AddItem(info, buffer[index + 1]); + } + + menu.ExitBackButton = true; + menu.ExitButton = true; + // Add +3 to the index for the 3 "Delete ..." buttons + // TODO: restore the delete index issue, use /7*7 + menu.DisplayAt(client, 0, MENU_TIME_FOREVER); +} +void ShowEditList(int client, int index = 0) { + Menu menu = new Menu(EditHandler); + menu.SetTitle("Edit Prop"); + + char info[8]; + char buffer[32]; + for(int i = 0; i < g_spawnedItems.Length; i++) { + int ref = GetSpawnedItem(i); + if(ref == -1) continue; + IntToString(i, info, sizeof(info)); + GetEntPropString(ref, Prop_Data, "m_ModelName", buffer, sizeof(buffer)); + index = FindCharInString(buffer, '/', true); + if(index != -1) + menu.AddItem(info, buffer[index + 1]); + } + + menu.ExitBackButton = true; + menu.ExitButton = true; + // Add +2 to the index for the two "Delete ..." buttons + menu.DisplayAt(client, index, MENU_TIME_FOREVER); +} +void ShowCategoryList(int client, ArrayList categoryList = null) { + LoadCategories(); + Menu menu = new Menu(SpawnCategoryHandler); + menu.SetTitle("Choose a category"); + CategoryData cat; + char info[4]; + // No category list provided, use the global one. + PrintToServer("ShowCategoryList (root = %b)", categoryList == null); + if(categoryList == null) { + categoryList = g_categories; + } + g_PropData[client].SetList(categoryList, false); + for(int i = 0; i < categoryList.Length; i++) { + categoryList.GetArray(i, cat); + Format(info, sizeof(info), "%d", i); + // TODO: maybe add > folder indicator + menu.AddItem(info, cat.name); + } + menu.ExitBackButton = true; + menu.ExitButton = true; + // Round to page instead of index (int division) + int index = g_PropData[client].lastCategoryIndex / 7 * 7; + menu.DisplayAt(client, index, MENU_TIME_FOREVER); +} +void ShowItemMenuAny(int client, ArrayList items, const char[] title = "", bool clearArray = false, const char[] classnameOverride = "") { + if(items == null) { + items = g_PropData[client].listBuffer; + if(items == null) { + LogError("Items is null and listBuffer is null as well"); + } + } else { + g_PropData[client].SetList(items, clearArray); + g_PropData[client].lastItemIndex = 0; + strcopy(g_PropData[client].classnameOverride, 32, classnameOverride); + } + if(items.Length == 0) { + PrintToChat(client, "\x04[Editor]\x01 No items to show."); + return; + } + Menu itemMenu = new Menu(SpawnItemHandler); + if(title[0] != '\0') + itemMenu.SetTitle(title); + ItemData item; + char info[128+64+8]; + for(int i = 0; i < items.Length; i++) { + items.GetArray(i, item); + // Sadly need to duplicate item.name. + Format(info, sizeof(info), "%d|%s|%s", i, item.model, item.name); + itemMenu.AddItem(info, item.name); + } + itemMenu.ExitBackButton = true; + itemMenu.ExitButton = true; + // We don't want to start at the index but the page of the index + int index = (g_PropData[client].lastItemIndex / 7) * 7; + itemMenu.DisplayAt(client, index, MENU_TIME_FOREVER); +} + +// Calls ShowItemMenuAny with the correct category automatically +bool ShowItemMenu(int client, int index) { + if(g_PropData[client].lastCategoryIndex != index) { + g_PropData[client].lastCategoryIndex = index; + g_PropData[client].lastItemIndex = 0; //Reset + } + CategoryData category; + // Use the list in the buffer + g_PropData[client].listBuffer.GetArray(index, category); + if(category.items == null) { + LogError("Category %s has null items array (index=%d)", category.name, index); + } else if(category.hasItems) { + PrintToServer("Selected category has item entries, showing item menu"); + ShowItemMenuAny(client, category.items, category.name, false, category.classnameOverride); + } else { + PrintToServer("Selected category has nested categories, showing"); + // Has nested categories + // Reset the category index for nested + g_PropData[client].lastCategoryIndex = 0; + g_PropData[client].SetList(category.items); + ShowCategoryList(client, g_PropData[client].listBuffer); + } + return true; +} \ No newline at end of file diff --git a/scripting/include/hats/props/methods.sp b/scripting/include/hats/props/methods.sp new file mode 100644 index 0000000..13d0516 --- /dev/null +++ b/scripting/include/hats/props/methods.sp @@ -0,0 +1,479 @@ + +ArrayList LoadSaves() { + char path[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/saves/%s", g_currentMap); + FileType fileType; + DirectoryListing listing = OpenDirectory(path); + if(listing == null) return null; + char buffer[64]; + ArrayList saves = new ArrayList(ByteCountToCells(64)); + while(listing.GetNext(buffer, sizeof(buffer), fileType)) { + if(buffer[0] == '.') continue; + saves.PushString(buffer); + } + delete listing; + return saves; +} + +ArrayList g_previewItems; + +bool LoadSave(const char[] save, bool asPreview = false) { + char path[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/saves/%s/%s", g_currentMap, save); + // ArrayList savedItems = new ArrayList(sizeof(SaveData)); + File file = OpenFile(path, "r"); + if(file == null) return false; + char buffer[256]; + if(asPreview) { + // Kill any previous preview + if(g_previewItems != null) ClearSavePreview(); + g_previewItems = new ArrayList(); + } + SaveData data; + while(file.ReadLine(buffer, sizeof(buffer))) { + if(buffer[0] == '#') continue; + data.Deserialize(buffer); + int entity = -1; + if(data.type == Build_Physics) + entity = CreateEntityByName("prop_physics"); + else + entity = CreateEntityByName("prop_dynamic"); + if(entity == -1) continue; + PrecacheModel(data.model); + DispatchKeyValue(entity, "model", data.model); + DispatchKeyValue(entity, "targetname", "saved_prop"); + if(asPreview) { + DispatchKeyValue(entity, "rendermode", "1"); + DispatchKeyValue(entity, "solid", "0"); + } else { + DispatchKeyValue(entity, "solid", data.type == Build_NonSolid ? "0" : "6"); + } + TeleportEntity(entity, data.origin, data.angles, NULL_VECTOR); + if(!DispatchSpawn(entity)) continue; + int alpha = asPreview ? 200 : data.color[3]; + SetEntityRenderColor(entity, data.color[0], data.color[1], data.color[2], alpha); + + if(asPreview) + g_savedItems.Push(EntIndexToEntRef(entity)); + else + AddSpawnedItem(entity); + } + delete file; + if(asPreview) { + delete g_previewItems; + } + return true; +} + +void ClearSavePreview() { + if(g_previewItems != null) { + for(int i = 0; i < g_previewItems.Length; i++) { + int ref = g_previewItems.Get(i); + if(IsValidEntity(ref)) { + RemoveEntity(ref); + } + } + delete g_previewItems; + } + g_pendingSaveClient = 0; +} + +void AddSpawnedItem(int entity, int client = 0) { + int index = g_spawnedItems.Push(EntIndexToEntRef(entity)); + if(client == 0) + g_spawnedItems.Set(index, 0, 1); + else + g_spawnedItems.Set(index, GetClientUserId(client), 1); +} + +bool CreateSave(const char[] name) { + char path[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/saves/%s", g_currentMap); + CreateDirectory(path, 509); + Format(path, sizeof(path), "%s/%s.txt", path, name); + File file = OpenFile(path, "w"); + if(file == null) { + PrintToServer("[Editor] Could not save: %s", path); + return false; + } + char buffer[132]; + SaveData data; + for(int i = 0; i < g_spawnedItems.Length; i++) { + int ref = g_spawnedItems.Get(i); + if(IsValidEntity(ref)) { + data.FromEntity(ref); + data.Serialize(buffer, sizeof(buffer)); + file.WriteLine("%s", buffer); + } + } + file.Flush(); + delete file; + return true; +} + +void UnloadSave() { + if(g_savedItems != null) { + delete g_savedItems; + } +} + +public void LoadCategories() { + if(g_categories != null) return; + g_categories = new ArrayList(sizeof(CategoryData)); + char path[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/models"); + LoadFolder(g_categories, path); + g_categories.SortCustom(SortCategories); +} +int SortCategories(int index1, int index2, ArrayList array, Handle hndl) { + CategoryData cat1; + array.GetArray(index1, cat1); + CategoryData cat2; + array.GetArray(index2, cat2); + return strcmp(cat1.name, cat2.name); +} +public void UnloadCategories() { + if(g_categories == null) return; + _UnloadCategories(g_categories); + delete g_categories; +} +void _UnloadCategories(ArrayList list) { + CategoryData cat; + for(int i = 0; i < list.Length; i++) { + list.GetArray(i, cat); + _UnloadCategory(cat); + } +} +void _UnloadCategory(CategoryData cat) { + // Is a sub-category: + if(!cat.hasItems) { + _UnloadCategories(cat.items); + } + delete cat.items; +} + +void LoadFolder(ArrayList parent, const char[] rootPath) { + char buffer[PLATFORM_MAX_PATH]; + FileType fileType; + DirectoryListing listing = OpenDirectory(rootPath); + if(listing == null) { + LogError("Cannot open \"%s\"", rootPath); + } + while(listing.GetNext(buffer, sizeof(buffer), fileType)) { + if(fileType == FileType_Directory) { + // TODO: support subcategory + if(buffer[0] == '.') continue; + CategoryData data; + Format(data.name, sizeof(data.name), "%s>>", buffer); + data.items = new ArrayList(sizeof(CategoryData)); + + Format(buffer, sizeof(buffer), "%s/%s", rootPath, buffer); + LoadFolder(data.items, buffer); + parent.PushArray(data); + } else if(fileType == FileType_File) { + Format(buffer, sizeof(buffer), "%s/%s", rootPath, buffer); + LoadProps(parent, buffer); + } + } + delete listing; +} + +void LoadProps(ArrayList parent, const char[] filePath) { + File file = OpenFile(filePath, "r"); + if(file == null) { + PrintToServer("[Props] Cannot open file \"%s\"", filePath); + return; + } + CategoryData category; + category.items = new ArrayList(sizeof(ItemData)); + category.hasItems = true; + char buffer[128]; + if(!file.ReadLine(buffer, sizeof(buffer))) { + delete file; + return; + } + ReplaceString(buffer, sizeof(buffer), "\n", ""); + ReplaceString(buffer, sizeof(buffer), "\r", ""); + Format(category.name, sizeof(category.name), "%s>", buffer); + while(file.ReadLine(buffer, sizeof(buffer))) { + if(buffer[0] == '#') continue; + ReplaceString(buffer, sizeof(buffer), "\n", ""); + ReplaceString(buffer, sizeof(buffer), "\r", ""); + ItemData item; + int index = SplitString(buffer, ":", item.model, sizeof(item.model)); + if(index == -1) { + index = SplitString(buffer, " ", item.model, sizeof(item.model)); + if(index == -1) { + // No name provided, use the model's filename + index = FindCharInString(buffer, '/', true); + strcopy(item.name, sizeof(item.name), item.model[index + 1]); + } else { + strcopy(item.name, sizeof(item.name), buffer[index]); + } + category.items.PushArray(item); + } else if(StrEqual(item.model, "Classname")) { + strcopy(category.classnameOverride, sizeof(category.classnameOverride), buffer[index]); + } else if(StrEqual(item.model, "Type")) { + Format(category.classnameOverride, sizeof(category.classnameOverride), "_%s", buffer[index]); + } + } + parent.PushArray(category); + delete file; +} +bool recentsChanged = false; +bool SaveRecents() { + if(!recentsChanged) return true; // Nothing to do, nothing changed + if(g_recentItems == null) return false; + char path[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/recents_cache.csv"); + File file = OpenFile(path, "w"); + if(file == null) { + PrintToServer("[Editor] Could not write to %s", path); + return false; + } + StringMapSnapshot snapshot = g_recentItems.Snapshot(); + char model[128]; + RecentEntry entry; + for(int i = 0; i < snapshot.Length; i++) { + snapshot.GetKey(i, model, sizeof(model)); + g_recentItems.GetArray(model, entry, sizeof(entry)); + file.WriteLine("%s,%s,%d", model, entry.name, entry.count); + } + file.Flush(); + delete file; + delete snapshot; + recentsChanged = false; + return true; +} +bool LoadRecents() { + return false; + if(g_recentItems != null) delete g_recentItems; + char path[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/recents_cache.csv"); + File file = OpenFile(path, "r"); + if(file == null) return false; + g_recentItems = new StringMap(); + char buffer[128+64+16]; + char model[128]; + RecentEntry entry; + while(file.ReadLine(buffer, sizeof(buffer))) { + int index = SplitString(buffer, ",", model, sizeof(model)); + index += SplitString(buffer[index], ",", entry.name, sizeof(entry.name)); + entry.count = StringToInt(buffer[index]); + g_recentItems.SetArray(model, entry, sizeof(entry)); + } + delete file; + return true; +} + +// Returns an ArrayList of all the recents +ArrayList GetRecentsItemList() { + ArrayList items = new ArrayList(sizeof(ItemData)); + StringMapSnapshot snapshot = g_recentItems.Snapshot(); + char model[128]; + RecentEntry entry; + ItemData item; + for(int i = 0; i < snapshot.Length; i++) { + snapshot.GetKey(i, model, sizeof(model)); + g_recentItems.GetArray(model, entry, sizeof(entry)); + strcopy(item.model, sizeof(item.model), model); + strcopy(item.name, sizeof(item.name), entry.name); + } + // This is pretty expensive in terms of allocations but shrug + items.SortCustom(SortRecents); + delete snapshot; + return items; +} + +int SortRecents(int index1, int index2, ArrayList array, Handle handle) { + ItemData data1; + array.GetArray(index1, data1); + ItemData data2; + array.GetArray(index2, data2); + + int count1, count2; + RecentEntry entry; + if(g_recentItems.GetArray(data1.model, entry, sizeof(entry))) return 0; //skip if somehow no entry + count1 = entry.count; + if(g_recentItems.GetArray(data2.model, entry, sizeof(entry))) return 0; //skip if somehow no entry + count2 = entry.count; + return count2 - count1; // desc +} + +void AddRecent(const char[] model, const char[] name) { + if(g_recentItems == null) { + if(!LoadRecents()) return; + } + RecentEntry entry; + if(!g_recentItems.GetArray(model, entry, sizeof(entry))) { + entry.count = 0; + strcopy(entry.name, sizeof(entry.name), name); + } + entry.count++; + recentsChanged = true; + g_recentItems.SetArray(model, entry, sizeof(entry)); +} +public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) { + if(!g_PropData[client].isSearchActive) { + return Plugin_Continue; + } + DoSearch(client, sArgs); + return Plugin_Handled; +} +void DoSearch(int client, const char[] query) { + ArrayList results = SearchItems(query); + if(results.Length == 0) { + CPrintToChat(client, "\x04[Editor]\x01 No results found. :("); + } else { + ShowItemMenuAny(client, results, "", true); + } + g_PropData[client].isSearchActive = false; +} +// Gets the index of the spawned item, starting at index. negative to go from back +int GetSpawnedIndex(int client, int index) { + int userid = GetClientUserId(client); + if(index >= 0) { + for(int i = index; i < g_spawnedItems.Length; i++) { + int spawnedBy = g_spawnedItems.Get(i, 1); + if(spawnedBy == userid) { + return i; + } + } + } else { + for(int i = g_spawnedItems.Length + index; i >= 0; i--) { + int spawnedBy = g_spawnedItems.Get(i, 1); + if(spawnedBy == userid) { + return i; + } + } + } + return -1; +} +#define MAX_SEARCH_RESULTS 10 +ArrayList SearchItems(const char[] query) { + // We have to put it into SearchData enum struct, then convert it back to ItemResult + LoadCategories(); + ArrayList results = new ArrayList(sizeof(SearchData)); + _searchCategory(results, g_categories, query); + results.SortCustom(SortSearch); + ArrayList items = new ArrayList(sizeof(ItemData)); + ItemData item; + SearchData data; + for(int i = 0; i < results.Length; i++) { + results.GetArray(i, data); + PrintToConsoleAll("%d | data=\"%s\"", i, data.model); + item.FromSearchData(data); + PrintToConsoleAll("%d | item=\"%s\"", i, item.model); + items.PushArray(item); + } + delete results; + return items; +} + +int SortSearch(int index1, int index2, ArrayList array, Handle handle) { + SearchData data1; + array.GetArray(index1, data1); + SearchData data2; + array.GetArray(index2, data2); + return data1.index - data2.index; +} + +void _searchCategory(ArrayList results, ArrayList categories, const char[] query) { + CategoryData cat; + if(categories == null) return; + for(int i = 0; i < categories.Length; i++) { + categories.GetArray(i, cat); + if(cat.hasItems) { + //cat.items is of CatetoryData + if(!_searchItems(results, cat.items, query)) return; + } else { + //cat.items is of ItemData + _searchCategory(results, cat.items, query); + } + } +} +bool _searchItems(ArrayList results, ArrayList items, const char[] query) { + ItemData item; + SearchData search; + for(int i = 0; i < items.Length; i++) { + items.GetArray(i, item); + int searchIndex = StrContains(item.name, query, false); + if(searchIndex > -1) { + search.FromItemData(item); + search.index = searchIndex; + results.PushArray(search); + if(results.Length > MAX_SEARCH_RESULTS) return false; + } + } + return true; +} + +int GetSpawnedItem(int index) { + if(index < 0 || index >= g_spawnedItems.Length) return -1; + int ref = g_spawnedItems.Get(index); + if(!IsValidEntity(ref)) { + g_spawnedItems.Erase(index); + return -1; + } + return ref; +} + +bool RemoveSpawnedProp(int ref) { + // int ref = EntIndexToEntRef(entity); + int index = g_spawnedItems.FindValue(ref); + if(index > -1) { + g_spawnedItems.Erase(index); + return true; + } + return false; +} + +void EndDeleteTool(int client, bool deleteEntities = false) { + if(g_PropData[client].markedProps != null) { + int count; + for(int i = 0; i < g_PropData[client].markedProps.Length; i++) { + int ref = g_PropData[client].markedProps.Get(i); + if(IsValidEntity(ref)) { + count++; + if(deleteEntities) { + RemoveSpawnedProp(ref); + RemoveEntity(ref); + } + else L4D2_RemoveEntityGlow(EntRefToEntIndex(ref)); + } + } + delete g_PropData[client].markedProps; + if(deleteEntities) + PrintToChat(client, "\x04[Editor]\x01 \x05%d\x01 entities deleted", count); + else + PrintToChat(client, "\x04[Editor]\x01 Delete tool cancelled"); + } +} + +int DeleteAll(int onlyPlayer = 0) { + int userid = onlyPlayer > 0 ? GetClientUserId(onlyPlayer) : 0; + int count; + for(int i = 0; i < g_spawnedItems.Length; i++) { + int ref = g_spawnedItems.Get(i); + int spawnedBy = g_spawnedItems.Get(i, 1); + // Skip if wishing to only delete certain items: + if(onlyPlayer != 0 && spawnedBy != userid) continue; + if(IsValidEntity(ref)) { + RemoveEntity(ref); + } + g_spawnedItems.Erase(i); + count++; + } + return count; +} + +#define SHOW_HINT_MIN_DURATION 600 // 600 s (10min) +void ShowHint(int client) { + int time = GetTime(); + if(time - g_PropData[client].lastShowedHint < SHOW_HINT_MIN_DURATION) return; + PrintToChat(client, "\x05R: \x01Change Mode"); + PrintToChat(client, "\x05Middle Click: \x01Cancel Placement \x05Shift + Middle Click: \x01Place \x05Ctrl + Middle Click: \x01Change Type"); + PrintToChat(client, "\x05E: \x01Rotate (hold, use mouse) \x05Left Click: \x01Change Axis \x05Right Click: \x01Snap Angle"); + + g_PropData[client].lastShowedHint = time; +} diff --git a/scripting/include/jutils.inc b/scripting/include/jutils.inc index d8bd945..8d32ef5 100644 --- a/scripting/include/jutils.inc +++ b/scripting/include/jutils.inc @@ -915,7 +915,8 @@ stock void GlowPoint(const float pos[3], float lifetime = 5.0) { stock void GlowEntity(int entity, float lifetime = 10.0, int glowColor[3] = _glowColor) { L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, glowColor, false); - CreateTimer(lifetime, Timer_ClearGlow, EntIndexToEntRef(entity)); + if(lifetime > 0.0) + CreateTimer(lifetime, Timer_ClearGlow, EntIndexToEntRef(entity)); } Action Timer_ClearGlow(Handle h, int ref) { diff --git a/scripting/l4d2_crescendo_control.sp b/scripting/l4d2_crescendo_control.sp index 678f2e0..092938a 100644 --- a/scripting/l4d2_crescendo_control.sp +++ b/scripting/l4d2_crescendo_control.sp @@ -298,7 +298,7 @@ public Action L4D2_CGasCan_EventKilled(int gascan, int &inflictor, int &attacker float activatorFlow = L4D2Direct_GetFlowDistance(attacker); GroupResult result; PrintToConsoleAll("[CC] Gascan Shot by %N", attacker); - ComputeGroups(result, activatorFlow); + // ComputeGroups(result, activatorFlow); AdminId admin = GetUserAdmin(attacker); if(admin != INVALID_ADMIN_ID && admin.HasFlag(Admin_Custom1)) { diff --git a/scripting/l4d2_extraplayeritems.sp b/scripting/l4d2_extraplayeritems.sp index ba1339d..c43e4df 100644 --- a/scripting/l4d2_extraplayeritems.sp +++ b/scripting/l4d2_extraplayeritems.sp @@ -1397,12 +1397,7 @@ void SetExtraKits(int playerCount) { if(GetRandomFloat() < 0.3 && averageTeamHP <= 80.0) ++extraPlayers; - //If hAddExtraKits TRUE: Append to previous, FALSE: Overwrite - if(hAddExtraKits.BoolValue) - g_extraKitsAmount += extraPlayers; - else - g_extraKitsAmount = extraPlayers; - + g_extraKitsAmount += extraPlayers; g_extraKitsStart = g_extraKitsAmount; } diff --git a/scripting/l4d2_hats.sp b/scripting/l4d2_hats.sp index e798a18..351dcfa 100644 --- a/scripting/l4d2_hats.sp +++ b/scripting/l4d2_hats.sp @@ -38,20 +38,16 @@ ConVar cvar_sm_hats_max_distance; TopMenu g_topMenu; -int g_lastCategoryIndex[MAXPLAYERS+1]; -int g_lastItemIndex[MAXPLAYERS+1]; -int g_lastShowedHint[MAXPLAYERS+1]; -bool g_isSearchActive[MAXPLAYERS+1]; - char g_currentMap[64]; -#include +//int g_markedMode + +#include #include #include -#include +#include -public Plugin myinfo = -{ +public Plugin myinfo = { name = "L4D2 Hats", author = "jackzmc", description = "", @@ -81,8 +77,8 @@ public void OnPluginStart() { RegConsoleCmd("sm_hat", Command_DoAHat, "Hats"); RegAdminCmd("sm_hatf", Command_DoAHat, ADMFLAG_ROOT, "Hats"); RegAdminCmd("sm_mkwall", Command_MakeWall, ADMFLAG_CHEATS); - RegAdminCmd("sm_walls", Command_ManageWalls, ADMFLAG_CHEATS); - RegAdminCmd("sm_wall", Command_ManageWalls, ADMFLAG_CHEATS); + RegAdminCmd("sm_edit", Command_Editor, ADMFLAG_CHEATS); + RegAdminCmd("sm_wall", Command_Editor, ADMFLAG_CHEATS); RegAdminCmd("sm_prop", Command_Props, ADMFLAG_CHEATS); RegConsoleCmd("sm_hatp", Command_DoAHatPreset); @@ -110,7 +106,7 @@ public void OnPluginStart() { } for(int i = 1; i <= MaxClients; i++) { - WallBuilder[i].Reset(true); + Editor[i].Reset(true); hatData[i].yeetGroundTimer = null; } @@ -133,7 +129,7 @@ public void OnLibraryRemoved(const char[] name) { public void OnEnterSaferoom(Event event, const char[] name, bool dontBroadcast) { int userid = event.GetInt("userid"); int client = GetClientOfUserId(userid); - if(client > 0 && client <= MaxClients && IsValidClient(client) && GetClientTeam(client) == 2) { + if(client > 0 && client <= MaxClients && IsValidClient(client) && GetClientTeam(client) == 2 && !IsFakeClient(client)) { inSaferoom[client] = true; if(cvar_sm_hats_flags.IntValue & view_as(HatConfig_NoSaferoomHats)) { if(HasHat(client) && !HasFlag(client, HAT_PRESET)) { @@ -464,6 +460,7 @@ void ChooseRandomPosition(float pos[3], int ignoreClient = 0) { } } +bool g_inRotate[MAXPLAYERS+1]; public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2]) { float tick = GetGameTime(); ////////////////////////////// @@ -567,13 +564,52 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3 ////////////////////////////// // OnPlayerRunCmd :: ENTITY EDITOR ///////////////////////////// - if(WallBuilder[client].IsActive() && WallBuilder[client].CheckEntity(client)) { + if(g_pendingSaveClient == client) { + if(buttons & IN_ZOOM) { + ClearSavePreview(); + if(buttons & IN_SPEED) { + LoadSave(g_pendingSaveName, false); + } + } + } else if(g_PropData[client].markedProps != null) { + SetWeaponDelay(client, 0.5); + if(tick - cmdThrottle[client] >= 0.20) { + if(buttons & IN_ATTACK) { + int entity = GetLookingEntity(client, Filter_ValidHats); + if(entity > 0) { + g_PropData[client].markedProps.Push(EntIndexToEntRef(entity)); + GlowEntity(entity, 0.0, GLOW_RED); + } else { + PrintHintText(client, "No entity found"); + } + } else if(buttons & IN_ATTACK2) { + int entity = GetLookingEntity(client, Filter_ValidHats); + if(entity > 0) { + int ref = EntIndexToEntRef(entity); + int index = g_PropData[client].markedProps.FindValue(ref); + if(index > -1) { + g_PropData[client].markedProps.Erase(index); + L4D2_RemoveEntityGlow(entity); + } + } + } else if(buttons & IN_USE) { + if(buttons & IN_SPEED) { + //Delete + EndDeleteTool(client, true); + } else if(buttons & IN_DUCK) { + //Cancel + EndDeleteTool(client, false); + } + } + cmdThrottle[client] = tick; + } + } else if(Editor[client].IsActive() && Editor[client].CheckEntity(client)) { if(buttons & IN_USE && buttons & IN_RELOAD) { ClientCommand(client, "sm_wall done"); return Plugin_Handled; } bool allowMove = true; - switch(WallBuilder[client].mode) { + switch(Editor[client].mode) { case MOVE_ORIGIN: { SetWeaponDelay(client, 0.5); @@ -581,34 +617,42 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3 bool isRotate; int flags = GetEntityFlags(client); if(buttons & IN_USE && ~buttons & IN_ZOOM) { + if(!g_inRotate[client]) { + g_inRotate[client] = true; + } if(buttons & IN_SPEED) { - WallBuilder[client].ToggleCollision(client, tick); + Editor[client].ToggleCollision(client, tick); + } else if(buttons & IN_DUCK) { + Editor[client].ToggleCollisionRotate(client, tick); } else { - PrintCenterText(client, "%.1f %.1f %.1f", WallBuilder[client].angles[0], WallBuilder[client].angles[1], WallBuilder[client].angles[2]); + // PrintCenterText(client, "%.1f %.1f %.1f", Editor[client].angles[0], Editor[client].angles[1], Editor[client].angles[2]); isRotate = true; SetEntityFlags(client, flags |= FL_FROZEN); - if(buttons & IN_ATTACK) WallBuilder[client].CycleAxis(client, tick); - else if(buttons & IN_ATTACK2) WallBuilder[client].CycleSnapAngle(client, tick); + if(buttons & IN_ATTACK) Editor[client].CycleAxis(client, tick); + else if(buttons & IN_ATTACK2) Editor[client].CycleSnapAngle(client, tick); // Rotation control: if(tick - cmdThrottle[client] > 0.20) { - if(WallBuilder[client].axis == 0) { - if(mouse[1] > 10) WallBuilder[client].angles[0] += WallBuilder[client].snapAngle; - else if(mouse[1] < -10) WallBuilder[client].angles[0] -= WallBuilder[client].snapAngle; - } else if(WallBuilder[client].axis == 1) { - if(mouse[0] > 10) WallBuilder[client].angles[1] += WallBuilder[client].snapAngle; - else if(mouse[0] < -10) WallBuilder[client].angles[1] -= WallBuilder[client].snapAngle; + // Turn off rotate when player wants rotate + Editor[client].hasCollisionRotate = false; + if(Editor[client].axis == 3) { + if(mouse[1] > 10) Editor[client].angles[2] += Editor[client].snapAngle; + else if(mouse[1] < -10) Editor[client].angles[2] -= Editor[client].snapAngle; } else { - if(mouse[1] > 10) WallBuilder[client].angles[2] += WallBuilder[client].snapAngle; - else if(mouse[1] < -10) WallBuilder[client].angles[2] -= WallBuilder[client].snapAngle; + if(mouse[0] > 10) Editor[client].angles[Editor[client].axis] += Editor[client].snapAngle; + else if(mouse[0] < -10) Editor[client].angles[Editor[client].axis] -= Editor[client].snapAngle; + } cmdThrottle[client] = tick; } } } else { + if(g_inRotate[client]) { + g_inRotate[client] = false; + } // Move position - if(buttons & IN_ATTACK) WallBuilder[client].moveDistance++; - else if(buttons & IN_ATTACK2) WallBuilder[client].moveDistance--; + if(buttons & IN_ATTACK) Editor[client].moveDistance++; + else if(buttons & IN_ATTACK2) Editor[client].moveDistance--; } // Clear IN_FROZEN when no longer rotate @@ -616,8 +660,7 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3 flags = flags & ~FL_FROZEN; SetEntityFlags(client, flags); } - - GetCursorLimited2(client, WallBuilder[client].moveDistance, WallBuilder[client].origin, Filter_IgnorePlayerAndWall, WallBuilder[client].hasCollision); + GetEditorPosition(client, Filter_IgnorePlayerAndWall); } case SCALE: { SetWeaponDelay(client, 0.5); @@ -625,74 +668,77 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3 bool sizeChanged = false; switch(buttons) { case IN_MOVELEFT: { - WallBuilder[client].size[0] -=WallBuilder[client].moveSpeed; - if(WallBuilder[client].size[0] <= 0.0) WallBuilder[client].size[0] = 0.0; + Editor[client].size[0] -=Editor[client].moveSpeed; + if(Editor[client].size[0] <= 0.0) Editor[client].size[0] = 0.0; sizeChanged = true; } case IN_MOVERIGHT: { - WallBuilder[client].size[0] += WallBuilder[client].moveSpeed; + Editor[client].size[0] += Editor[client].moveSpeed; sizeChanged = true; } case IN_FORWARD: { - WallBuilder[client].size[1]+= WallBuilder[client].moveSpeed; + Editor[client].size[1]+= Editor[client].moveSpeed; sizeChanged = true; } case IN_BACK: { - WallBuilder[client].size[1] -= WallBuilder[client].moveSpeed; - if(WallBuilder[client].size[1] <= 0.0) WallBuilder[client].size[1] = 0.0; + Editor[client].size[1] -= Editor[client].moveSpeed; + if(Editor[client].size[1] <= 0.0) Editor[client].size[1] = 0.0; sizeChanged = true; } case IN_JUMP: { - WallBuilder[client].size[2] += WallBuilder[client].moveSpeed; + Editor[client].size[2] += Editor[client].moveSpeed; sizeChanged = true; } case IN_DUCK: { - if(WallBuilder[client].size[2] <= 0.0) WallBuilder[client].size[2] = 0.0; - WallBuilder[client].size[2] -= WallBuilder[client].moveSpeed; + if(Editor[client].size[2] <= 0.0) Editor[client].size[2] = 0.0; + Editor[client].size[2] -= Editor[client].moveSpeed; sizeChanged = true; } - case IN_USE: WallBuilder[client].CycleSpeed(client, tick); + case IN_USE: Editor[client].CycleSpeed(client, tick); } if(sizeChanged) { - WallBuilder[client].CalculateMins(); + Editor[client].CalculateMins(); } } case COLOR: { SetWeaponDelay(client, 0.5); - PrintCenterText(client, "%d %d %d %d", WallBuilder[client].color[0], WallBuilder[client].color[1], WallBuilder[client].color[2], WallBuilder[client].color[3]); + PrintCenterText(client, "%d %d %d %d", Editor[client].color[0], Editor[client].color[1], Editor[client].color[2], Editor[client].color[3]); if(buttons & IN_USE) { - WallBuilder[client].CycleColorComponent(client, tick); + Editor[client].CycleColorComponent(client, tick); } else if(buttons & IN_ATTACK) { - WallBuilder[client].color[WallBuilder[client].colorIndex]--; - if(WallBuilder[client].color[WallBuilder[client].colorIndex] < 0) { - WallBuilder[client].color[WallBuilder[client].colorIndex] = 0; + Editor[client].color[Editor[client].colorIndex]--; + if(Editor[client].color[Editor[client].colorIndex] < 0) { + Editor[client].color[Editor[client].colorIndex] = 0; } - WallBuilder[client].UpdateEntity(); + Editor[client].UpdateEntity(); allowMove = false; } else if(buttons & IN_ATTACK2) { - WallBuilder[client].color[WallBuilder[client].colorIndex]++; - if(WallBuilder[client].color[WallBuilder[client].colorIndex] > 255) { - WallBuilder[client].color[WallBuilder[client].colorIndex] = 255; + Editor[client].color[Editor[client].colorIndex]++; + if(Editor[client].color[Editor[client].colorIndex] > 255) { + Editor[client].color[Editor[client].colorIndex] = 255; } - WallBuilder[client].UpdateEntity(); + Editor[client].UpdateEntity(); allowMove = false; } } } if(buttons & IN_RELOAD) - WallBuilder[client].CycleMode(client, tick); // R: Cycle forward - else if(WallBuilder[client].flags & Edit_Preview && tick - cmdThrottle[client] >= 0.25 && buttons & IN_ZOOM) { + Editor[client].CycleMode(client, tick); // R: Cycle forward + else if(Editor[client].flags & Edit_Preview && tick - cmdThrottle[client] >= 0.25 && buttons & IN_ZOOM) { + buttons &= ~IN_ZOOM; if(buttons & IN_SPEED) { int entity; - WallBuilder[client].Create(entity); - int index = g_spawnedItems.Push(EntIndexToEntRef(entity)); - g_spawnedItems.Set(index, GetClientUserId(client), 1); + Editor[client].Create(entity); + AddSpawnedItem(entity, client); + char model[128]; + GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model)); + AddRecent(model, Editor[client].data); } else if(buttons & IN_DUCK) { - WallBuilder[client].CycleBuildType(client); + Editor[client].CycleBuildType(client); } else { - WallBuilder[client].Cancel(); + Editor[client].Cancel(); CPrintToChat(client, "\x04[Editor]\x01 Cancelled."); } cmdThrottle[client] = tick; } - WallBuilder[client].Draw(BUILDER_COLOR, 0.1, 0.1); + Editor[client].Draw(BUILDER_COLOR, 0.1, 0.1); return allowMove ? Plugin_Continue : Plugin_Handled; } @@ -749,12 +795,13 @@ public void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast public void OnClientDisconnect(int client) { tempGod[client] = false; - WallBuilder[client].Reset(); - g_isSearchActive[client] = false; - g_lastCategoryIndex[client] = 0; - g_lastItemIndex[client] = 0; - g_lastShowedHint[client] = 0; + Editor[client].Reset(); + g_PropData[client].Reset(); hatData[client].yeetGroundTimer = null; + if(g_pendingSaveClient == client) { + g_pendingSaveClient = 0; + ClearSavePreview(); + } ClearHat(client, true); } @@ -797,6 +844,7 @@ public void OnMapEnd() { ClearHats(); UnloadCategories(); UnloadSave(); + SaveRecents(); } public void OnPluginEnd() { ClearHats(); @@ -807,10 +855,10 @@ public void OnPluginEnd() { } } if(g_spawnedItems != null) { - for(int i = 0; i < g_spawnedItems.Length; i++) { - int ref = g_spawnedItems.Get(i); - RemoveEntity(ref); - } + // for(int i = 0; i < g_spawnedItems.Length; i++) { + // int ref = g_spawnedItems.Get(i); + // RemoveEntity(ref); + // } delete g_spawnedItems; } TriggerInput("prop_preview", "Kill"); @@ -846,7 +894,13 @@ stock bool Filter_NoPlayers(int entity, int mask, int data) { } stock bool Filter_IgnorePlayerAndWall(int entity, int mask, int data) { - return entity > MaxClients && entity != data && EntRefToEntIndex(WallBuilder[data].entity) != entity; + if(entity > MaxClients && entity != data && EntRefToEntIndex(Editor[data].entity) != entity) { + static char classname[16]; + GetEntityClassname(entity, classname, sizeof(classname)); + // Ignore infected + return !StrEqual(classname, "infected"); + } + return false; } @@ -943,21 +997,27 @@ stock float SnapTo(const float value, const float degree) { return float(RoundFloat(value / degree)) * degree; } -// Gets a position from where the cursor is upto distance away (basically <= distance, going against walls) -stock bool GetCursorLimited2(int client, float distance, float endPos[3], TraceEntityFilter filter, bool doCollide = true) { +stock bool GetEditorPosition(int client, TraceEntityFilter filter) { if (client > 0 && client <= MaxClients && IsClientInGame(client)) { float clientEye[3], clientAngle[3], direction[3]; GetClientEyePosition(client, clientEye); GetClientEyeAngles(client, clientAngle); GetAngleVectors(clientAngle, direction, NULL_VECTOR, NULL_VECTOR); - ScaleVector(direction, distance); - AddVectors(clientEye, direction, endPos); + ScaleVector(direction, Editor[client].moveDistance); + AddVectors(clientEye, direction, Editor[client].origin); - if(doCollide) { - TR_TraceRayFilter(clientEye, endPos, MASK_OPAQUE, RayType_EndPoint, filter, client); + if(Editor[client].hasCollision) { + TR_TraceRayFilter(clientEye, Editor[client].origin, MASK_OPAQUE, RayType_EndPoint, filter, client); if (TR_DidHit(INVALID_HANDLE)) { - TR_GetEndPosition(endPos); + TR_GetEndPosition(Editor[client].origin); + GetEntPropVector(Editor[client].entity, Prop_Send, "m_vecMins", direction); + Editor[client].origin[2] -= direction[2]; + if(Editor[client].hasCollisionRotate) { + TR_GetPlaneNormal(INVALID_HANDLE, Editor[client].angles); + GetVectorAngles(Editor[client].angles, Editor[client].angles); + Editor[client].angles[0] += 90.0; + } } } diff --git a/scripting/l4d2_spawn_props.sp b/scripting/l4d2_spawn_props.sp new file mode 100644 index 0000000..a73ed38 --- /dev/null +++ b/scripting/l4d2_spawn_props.sp @@ -0,0 +1,4417 @@ +#include +#include +#include +#pragma semicolon 1 +#pragma newdecls required +#define DEBUG 0 + +#define GETVERSION "3.4" +#define ARRAY_SIZE 5000 +#define MAX_PATHS 30 + +#define DESIRED_ADM_FLAGS ADMFLAG_UNBAN //Edit here the flags to fit your needs! + +#define RouteType_Easy 0 +#define RouteType_Medium 1 +#define RouteType_Hard 2 + +char FolderNames[][] = { + "addons/stripper", + "addons/stripper/maps", + "addons/stripper/routing", + "addons/stripper/plugin_cache" +}; + +TopMenu g_TopMenuHandle; + +int g_iCategory[MAXPLAYERS+1] = 0; +int g_iSubCategory[MAXPLAYERS+1] = 0; +int g_iFileCategory[MAXPLAYERS+1] = 0; +int g_iMoveCategory[MAXPLAYERS+1] = 0; +int g_iLastObject[MAXPLAYERS+1] = -1; +int g_iLastGrabbedObject[MAXPLAYERS+1] = -1; + +bool g_bSpawned[ARRAY_SIZE] = false; +bool g_bGrabbed[ARRAY_SIZE] = false; +bool g_bGrab[MAXPLAYERS+1] = false; +bool g_bUnsolid[ARRAY_SIZE] = false; +bool g_bLoaded = false; + +float g_vecEntityAngles[ARRAY_SIZE][3]; +float g_vecLastEntityAngles[MAXPLAYERS+1][3]; + +char g_sPath[128]; + +// Global variables to hold menu position +int g_iRotateMenuPosition[MAXPLAYERS+1] = 0; +int g_iMoveMenuPosition[MAXPLAYERS+1] = 0; +int g_iVehiclesMenuPosition[MAXPLAYERS+1] = 0; +int g_iFoliageMenuPosition[MAXPLAYERS+1] = 0; +int g_iFurnitureMenuPosition[MAXPLAYERS+1] = 0; +int g_iFurnishingsMenuPosition[MAXPLAYERS+1] = 0; +int g_iAppliancesMenuPosition[MAXPLAYERS+1] = 0; +int g_iBuildingsMenuPosition[MAXPLAYERS+1] = 0; +int g_iScaffoldingMenuPosition[MAXPLAYERS+1] = 0; +int g_iDoorsMenuPosition[MAXPLAYERS+1] = 0; +int g_iWindowsMenuPosition[MAXPLAYERS+1] = 0; +int g_iLightsMenuPosition[MAXPLAYERS+1] = 0; +int g_iSignssMenuPosition[MAXPLAYERS+1] = 0; +int g_iFencingMenuPosition[MAXPLAYERS+1] = 0; +int g_iRailingMenuPosition[MAXPLAYERS+1] = 0; +int g_iStairsMenuPosition[MAXPLAYERS+1] = 0; +int g_iOfficeMenuPosition[MAXPLAYERS+1] = 0; +int g_iStreetsMenuPosition[MAXPLAYERS+1] = 0; +int g_iFairgroundsMenuPosition[MAXPLAYERS+1] = 0; +int g_iMallMenuPosition[MAXPLAYERS+1] = 0; +int g_iConstructionMenuPosition[MAXPLAYERS+1] = 0; +int g_iGeneralMiscMenuPosition[MAXPLAYERS+1] = 0; +int g_iExteriorMiscMenuPosition[MAXPLAYERS+1] = 0; +int g_iInteriorMiscMenuPosition[MAXPLAYERS+1] = 0; +int g_iDebrisMenuPosition[MAXPLAYERS+1] = 0; +int g_iJunkMenuPosition[MAXPLAYERS+1] = 0; +int g_iPipesMenuPosition[MAXPLAYERS+1] = 0; +int g_iBodiesGenericMenuPosition[MAXPLAYERS+1] = 0; +int g_iBodiesSwampMenuPosition[MAXPLAYERS+1] = 0; +int g_iBodiesSugarMillMenuPosition[MAXPLAYERS+1] = 0; +int g_iBodiesCemetaryMenuPosition[MAXPLAYERS+1] = 0; +int g_iInfectedMenuPosition[MAXPLAYERS+1] = 0; +int g_iSkyboxMenuPosition[MAXPLAYERS+1] = 0; + +ConVar g_cvarPhysics; +ConVar g_cvarDynamic; +ConVar g_cvarStatic; +ConVar g_cvarVehicles; +ConVar g_cvarFoliage; +ConVar g_cvarFurniture; +ConVar g_cvarFurnishings; +ConVar g_cvarAppliances; +ConVar g_cvarBuildings; +ConVar g_cvarScaffolding; +ConVar g_cvarDoors; +ConVar g_cvarWindows; +ConVar g_cvarLights; +ConVar g_cvarSigns; +ConVar g_cvarFencing; +ConVar g_cvarRailing; +ConVar g_cvarStairs; +ConVar g_cvarOffice; +ConVar g_cvarStreets; +ConVar g_cvarFairgrounds; +ConVar g_cvarMall; +ConVar g_cvarConstruction; +ConVar g_cvarGeneralMisc; +ConVar g_cvarExteriorMisc; +ConVar g_cvarInteriorMisc; +ConVar g_cvarDebris; +ConVar g_cvarJunk; +ConVar g_cvarPipes; +ConVar g_cvarBodiesGeneric; +ConVar g_cvarBodiesSwamp; +ConVar g_cvarBodiesSugarMill; +ConVar g_cvarBodiesCemetary; +ConVar g_cvarInfected; +ConVar g_cvarSkybox; +ConVar g_cvarLog; +ConVar g_cvarAutoload; +ConVar g_cvarAutoloadType; + +public Plugin myinfo = +{ + name = "[L4D1/2] Objects Spawner", + author = "honorcode23 & $atanic $pirit & HarryPotter", + description = "Let admins spawn any kind of objects", + version = GETVERSION, + url = "http://forums.alliedmods.net/showthread.php?p=1186503" +} + +bool L4D2Version; +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + EngineVersion test = GetEngineVersion(); + + if( test == Engine_Left4Dead ) + { + L4D2Version = false; + } + else if( test == Engine_Left4Dead2 ) + { + L4D2Version = true; + } + else + { + strcopy(error, err_max, "Plugin only supports Left 4 Dead 1 & 2."); + return APLRes_SilentFailure; + } + + return APLRes_Success; +} + +public void OnPluginStart() +{ + LoadTranslations("l4d2_spawn_props.phrases"); + + CreateConVar("l4d2_spawn_props_version", GETVERSION, "Version of the Plugin", FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); //Version + g_cvarPhysics = CreateConVar("l4d2_spawn_props_physics", "1", "Enable the Physics Objects in the menu"); + g_cvarDynamic = CreateConVar("l4d2_spawn_props_dynamic", "1", "Enable the Dynamic (Non-solid) Objects in the menu"); + g_cvarStatic = CreateConVar("l4d2_spawn_props_static", "1", "Enable the Static (Solid) Objects in the menu"); + g_cvarVehicles = CreateConVar("l4d2_spawn_props_category_vehicles", "1", "Enable the Vehicles category"); + g_cvarFoliage = CreateConVar("l4d2_spawn_props_category_foliage", "1", "Enable the Foliage category"); + g_cvarFurniture = CreateConVar("l4d2_spawn_props_category_furniture", "1", "Enable the Furniture category"); + g_cvarFurnishings = CreateConVar("l4d2_spawn_props_category_furnishings", "1", "Enable the Furnishings category"); + g_cvarAppliances = CreateConVar("l4d2_spawn_props_category_appliances", "1", "Enable the appliances category"); + g_cvarBuildings = CreateConVar("l4d2_spawn_props_category_buildings", "1", "Enable the Buildings category"); + g_cvarScaffolding = CreateConVar("l4d2_spawn_props_category_scaffolding", "1", "Enable the Scaffolding category"); + g_cvarDoors = CreateConVar("l4d2_spawn_props_category_doors", "1", "Enable the Doors category"); + g_cvarWindows = CreateConVar("l4d2_spawn_props_category_windows", "1", "Enable the Windows category"); + g_cvarLights = CreateConVar("l4d2_spawn_props_category_lights", "1", "Enable the Lights category"); + g_cvarSigns = CreateConVar("l4d2_spawn_props_category_signs", "1", "Enable the Signs category"); + g_cvarFencing = CreateConVar("l4d2_spawn_props_category_fencing", "1", "Enable the Fencing category"); + g_cvarRailing = CreateConVar("l4d2_spawn_props_category_railing", "1", "Enable the Railing category"); + g_cvarStairs = CreateConVar("l4d2_spawn_props_category_stairs", "1", "Enable the Stairs category"); + g_cvarOffice = CreateConVar("l4d2_spawn_props_category_office", "1", "Enable the Office category"); + g_cvarStreets = CreateConVar("l4d2_spawn_props_category_streets", "1", "Enable the Streets category"); + g_cvarFairgrounds = CreateConVar("l4d2_spawn_props_category_fairgrounds", "1", "Enable the Fairgrounds category"); + g_cvarMall = CreateConVar("l4d2_spawn_props_category_mall", "1", "Enable the Mall category"); + g_cvarConstruction = CreateConVar("l4d2_spawn_props_category_construction", "1", "Enable the Construction category"); + g_cvarGeneralMisc = CreateConVar("l4d2_spawn_props_category_generalmisc", "1", "Enable the GeneralMisc category"); + g_cvarExteriorMisc = CreateConVar("l4d2_spawn_props_category_exteriormisc", "1", "Enable the ExteriorMisc category"); + g_cvarInteriorMisc = CreateConVar("l4d2_spawn_props_category_interiormisc", "1", "Enable the InteriorMisc category"); + g_cvarDebris = CreateConVar("l4d2_spawn_props_category_debris", "1", "Enable the Debris category"); + g_cvarJunk = CreateConVar("l4d2_spawn_props_category_junk", "1", "Enable the Junk category"); + g_cvarPipes = CreateConVar("l4d2_spawn_props_category_pipes", "1", "Enable the Pipes category"); + g_cvarBodiesGeneric = CreateConVar("l4d2_spawn_props_category_bodiesgeneric", "1", "Enable the BodiesGeneric category"); + g_cvarBodiesSwamp = CreateConVar("l4d2_spawn_props_category_bodiesswamp", "1", "Enable the BodiesSwamp category"); + g_cvarBodiesSugarMill = CreateConVar("l4d2_spawn_props_category_bodiessugarmill", "1", "Enable the BodiesSugarMill category"); + g_cvarBodiesCemetary = CreateConVar("l4d2_spawn_props_category_bodiescemetary", "1", "Enable the BodiesCemetary category"); + g_cvarInfected = CreateConVar("l4d2_spawn_props_category_infected", "1", "Enable the Infected category"); + g_cvarSkybox = CreateConVar("l4d2_spawn_props_category_skybox", "1", "Enable the Skybox category"); + g_cvarLog = CreateConVar("l4d2_spawn_props_log_actions", "0", "Log if an admin spawns an object?"); + g_cvarAutoload = CreateConVar("l4d2_spawn_props_autoload", "0", "Enable the plugin to auto load the cache?"); + g_cvarAutoloadType = CreateConVar("l4d2_spawn_props_autoload_different", "1", "Should the paths be different for the teams or not?"); + + RegAdminCmd("sm_spawnprop", CmdSpawnProp, DESIRED_ADM_FLAGS, "Spawns an object with the given information"); + RegAdminCmd("sm_savemap", CmdSaveMap, DESIRED_ADM_FLAGS, "Save all the spawned object in a stripper file"); + + RegAdminCmd("sm_prop_rotate", CmdRotate, DESIRED_ADM_FLAGS, "Rotates the last spawned object with the desired angles"); + RegAdminCmd("sm_prop_removelast", CmdRemoveLast, DESIRED_ADM_FLAGS, "Remove last spawned object"); + RegAdminCmd("sm_prop_removelook", CmdRemoveLook, DESIRED_ADM_FLAGS, "Remove the looking object"); + RegAdminCmd("sm_prop_removeall", CmdRemoveAll, DESIRED_ADM_FLAGS, "Remove all objects"); + RegAdminCmd("sm_prop_move", CmdMove, DESIRED_ADM_FLAGS, "Move an object with the desired movement type"); + RegAdminCmd("sm_prop_setang", CmdSetAngles, DESIRED_ADM_FLAGS, "Forces an object angles"); + RegAdminCmd("sm_prop_setpos", CmdSetPosition, DESIRED_ADM_FLAGS, "Sets the last object position"); + + RegAdminCmd("sm_debugprop", CmdDebugProp, ADMFLAG_ROOT, "DEBUG"); + + + AutoExecConfig(true, "l4d2_spawn_props"); + TopMenu topMenu; + if (LibraryExists("adminmenu") && ((topMenu = GetAdminTopMenu()) != null)) { + OnAdminMenuReady(topMenu); + } + + //DEV + RegAdminCmd("sm_spload", CmdLoad, DESIRED_ADM_FLAGS, "Load map"); + + //Events + if(L4D2Version) + { + HookEvent("survival_round_start", Event_SurvivalRoundStart); + HookEvent("scavenge_round_start", Event_ScavengeRoundStart); + } + HookEvent("round_start_post_nav", Event_RoundStart); + HookEvent("round_end", Event_RoundEnd); + + //Create required folders + BuildFileDirectories(); +} + + +public Action CmdDebugProp(int client, int args) +{ + char name[256]; + int Object = g_iLastObject[client]; + if(Object > 0 && IsValidEntity(Object)) + { + GetEntPropString(Object, Prop_Data, "m_iName", name, sizeof(name)); + PrintToChat(client, "prop: %s", name); + } + return Plugin_Handled; +} + +public void Event_SurvivalRoundStart(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if(g_cvarAutoload.BoolValue && !g_bLoaded) + { + g_bLoaded = true; + SpawnObjects(); + } +} + +public void Event_ScavengeRoundStart(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + LogSpawn("Scavenge Round Has Started"); + if(g_cvarAutoload.BoolValue && !g_bLoaded) + { + g_bLoaded = true; + SpawnObjects(); + } +} +public void Event_RoundStart(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if(g_cvarAutoload.BoolValue && g_cvarAutoloadType.BoolValue) + { + GetRandomMapPath(g_sPath, sizeof(g_sPath)); + } + LogSpawn("Normal Round Has Started"); + if(g_cvarAutoload.BoolValue && !g_bLoaded) + { + g_bLoaded = true; + SpawnObjects(); + } +} + +public void Event_RoundEnd(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + g_bLoaded = false; +} + +public void OnMapEnd() +{ + g_bLoaded = false; +} + +public void OnMapStart() +{ + for(int i=MaxClients; i < ARRAY_SIZE; i++) + { + g_bSpawned[i] = false; + g_bUnsolid[i] = false; + g_vecEntityAngles[i][0] = 0.0; + g_vecEntityAngles[i][1] = 0.0; + g_vecEntityAngles[i][2] = 0.0; + } + if(g_cvarAutoload.BoolValue && !g_cvarAutoloadType.BoolValue) + { + GetRandomMapPath(g_sPath, sizeof(g_sPath)); + } +} + +public Action CmdSpawnProp(int client, int args) +{ + if(args < 3) + { + PrintToChat(client, "[SM] Usage: sm_spawnprop [static | dynamic | physics] [cursor | origin]"); + return Plugin_Handled; + } + char arg1[256]; + char arg2[256]; + char arg3[256]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + GetCmdArg(3, arg3, sizeof(arg3)); + char model[256]; + strcopy(model, sizeof(model), arg1); + if(!IsModelPrecached(model)) + { + if(PrecacheModel(model) <= 0) + { + PrintToChat(client, "[SM] There was a problem spawning the selected model [ERROR: Invalid Model]"); + return Plugin_Handled; + } + } + if(StrContains(arg2, "static") >= 0) + { + float VecOrigin[3]; + float VecAngles[3]; + int prop = CreateEntityByName("prop_dynamic_override"); + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + SetEntProp(prop, Prop_Send, "m_nSolidType", 6); + if(strcmp(arg3, "cursor") == 0) + { + GetClientEyePosition(client, VecOrigin); + GetClientEyeAngles(client, VecAngles); + TR_TraceRayFilter(VecOrigin, VecAngles, MASK_OPAQUE, RayType_Infinite, TraceRayDontHitSelf, client); + if(TR_DidHit(null)) + { + TR_GetEndPosition(VecOrigin); + } + else + { + PrintToChat(client, "[SM] Vector out of world geometry. Spawning on current position instead"); + } + } + else if(strcmp(arg3, "origin") == 0) + { + GetClientEyePosition(client, VecOrigin); + GetClientEyeAngles(client, VecAngles); + } + else + { + PrintToChat(client, "[SM] Invalid spawn method specified. Use: [cursor | origin]"); + return Plugin_Handled; + } + VecAngles[0] = 0.0; + VecAngles[2] = 0.0; + g_vecLastEntityAngles[client][0] = VecAngles[0]; + g_vecLastEntityAngles[client][1] = VecAngles[1]; + g_vecLastEntityAngles[client][2] = VecAngles[2]; + g_iLastObject[client] = prop; + DispatchKeyValueVector(prop, "angles", VecAngles); + DispatchSpawn(prop); + TeleportEntity(prop, VecOrigin, NULL_VECTOR, NULL_VECTOR); + g_bSpawned[prop] = true; + g_vecEntityAngles[prop] = VecAngles; + char name[256]; + GetClientName(client, name, sizeof(name)); + LogSpawn("%s spawned a static object with model <%s>", name, model); + } + else if(StrContains(arg2, "dynamic") >= 0) + { + float VecOrigin[3]; + float VecAngles[3]; + int prop = CreateEntityByName("prop_dynamic_override"); + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + if(strcmp(arg3, "cursor") == 0 ) + { + GetClientEyePosition(client, VecOrigin); + GetClientEyeAngles(client, VecAngles); + TR_TraceRayFilter(VecOrigin, VecAngles, MASK_OPAQUE, RayType_Infinite, TraceRayDontHitSelf, client); + if(TR_DidHit(null)) + { + TR_GetEndPosition(VecOrigin); + } + else + { + PrintToChat(client, "[SM] Vector out of world geometry. Spawning on current position instead"); + } + } + else if(strcmp(arg3, "origin")== 0) + { + GetClientEyePosition(client, VecOrigin); + GetClientEyeAngles(client, VecAngles); + } + else + { + PrintToChat(client, "[SM] Invalid spawn method specified. Use: [cursor | origin]"); + return Plugin_Handled; + } + VecAngles[0] = 0.0; + VecAngles[2] = 0.0; + g_vecLastEntityAngles[client][0] = VecAngles[0]; + g_vecLastEntityAngles[client][1] = VecAngles[1]; + g_vecLastEntityAngles[client][2] = VecAngles[2]; + g_iLastObject[client] = prop; + DispatchKeyValueVector(prop, "angles", VecAngles); + DispatchSpawn(prop); + TeleportEntity(prop, VecOrigin, NULL_VECTOR, NULL_VECTOR); + g_bSpawned[prop] = true; + g_vecEntityAngles[prop] = VecAngles; + g_bUnsolid[prop] = true; + char name[256]; + GetClientName(client, name, sizeof(name)); + LogSpawn("%s spawned a dynamic object with model <%s>", name, model); + } + else if(StrContains(arg2, "physics") >= 0) + { + float VecOrigin[3]; + float VecAngles[3]; + int prop = CreateEntityByName("prop_physics_override"); + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + if(strcmp(arg3, "cursor")== 0) + { + GetClientEyePosition(client, VecOrigin); + GetClientEyeAngles(client, VecAngles); + TR_TraceRayFilter(VecOrigin, VecAngles, MASK_OPAQUE, RayType_Infinite, TraceRayDontHitSelf, client); + if(TR_DidHit(null)) + { + TR_GetEndPosition(VecOrigin); + } + else + { + PrintToChat(client, "[SM] Vector out of world geometry. Spawning on current position instead"); + } + } + else if(strcmp(arg3, "origin")== 0) + { + GetClientEyePosition(client, VecOrigin); + GetClientEyeAngles(client, VecAngles); + } + else + { + PrintToChat(client, "[SM] Invalid spawn method specified. Use: [cursor | origin]"); + return Plugin_Handled; + } + VecAngles[0] = 0.0; + VecAngles[2] = 0.0; + g_vecLastEntityAngles[client][0] = VecAngles[0]; + g_vecLastEntityAngles[client][1] = VecAngles[1]; + g_vecLastEntityAngles[client][2] = VecAngles[2]; + g_iLastObject[client] = prop; + DispatchKeyValueVector(prop, "angles", VecAngles); + DispatchSpawn(prop); + TeleportEntity(prop, VecOrigin, NULL_VECTOR, NULL_VECTOR); + g_bSpawned[prop] = true; + g_vecEntityAngles[prop] = VecAngles; + char name[256]; + GetClientName(client, name, sizeof(name)); + LogSpawn("%s spawned a physics object with model <%s>", name, model); + } + else + { + PrintToChat(client, "[SM] Invalid render mode. Use: [static | dynamic | physics]"); + return Plugin_Handled; + } + return Plugin_Handled; +} + +//Admin Menu ready +public void OnAdminMenuReady(Handle topmenu) +{ + if (topmenu == g_TopMenuHandle) + { + return; + } + g_TopMenuHandle = view_as(topmenu); + TopMenuObject menu_category_prop = g_TopMenuHandle.AddCategory("Object Spawner", Category_Handler); + + if (menu_category_prop != INVALID_TOPMENUOBJECT) + { + g_TopMenuHandle.AddItem("sm_spdelete", AdminMenu_Delete, menu_category_prop, "sm_spdelete", DESIRED_ADM_FLAGS); //Delete + g_TopMenuHandle.AddItem("sm_spedit", AdminMenu_Edit, menu_category_prop, "sm_spedit", DESIRED_ADM_FLAGS); //Edit + g_TopMenuHandle.AddItem("sm_spspawn", AdminMenu_Spawn, menu_category_prop, "sm_spspawn", DESIRED_ADM_FLAGS); //Spawn + g_TopMenuHandle.AddItem("sm_spsave", AdminMenu_Save, menu_category_prop, "sm_spsave", DESIRED_ADM_FLAGS); //Save + g_TopMenuHandle.AddItem("sm_spload", AdminMenu_Load, menu_category_prop, "sm_spload", DESIRED_ADM_FLAGS); //Load + } +} + +//Admin Category Name +public int Category_Handler(TopMenu topmenu, TopMenuAction action, TopMenuObject topobj_id, int param, char[] buffer, int maxlength) +{ + if(action == TopMenuAction_DisplayTitle) + { + Format(buffer, maxlength, Translate(param, "%t", "Select a task:")); + } + else if(action == TopMenuAction_DisplayOption) + { + Format(buffer, maxlength, "Spawn Objects (Old)"); + } +} +/* +////////////////////////////////////////////////////////////////////////////| + D E L E T E M E N U | +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| +*/ + +public void AdminMenu_Delete(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) +{ + if(action == TopMenuAction_DisplayOption) + { + Format(buffer, maxlength, Translate(param, "%t", "Delete Object")); + } + else if(action == TopMenuAction_SelectOption) + { + BuildDeleteMenu(param); + } +} + +Menu BuildDeleteMenu(int client) +{ + Menu menu = new Menu(MenuHandler_Delete); + menu.SetTitle("%T", "Select the delete task", client); + menu.AddItem("sm_spdeleteall", Translate(client, "%t", "Delete All Objects")); + menu.AddItem("sm_spdeletelook", Translate(client, "%t", "Delete Looking Object")); + menu.AddItem("sm_spdeletelast", Translate(client, "%t", "Delete Last Object")); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +Menu BuildDeleteAllAskMenu(int client) +{ + Menu menu = new Menu(MenuHandler_DA_Ask); + menu.SetTitle("%T", "Are you sure(Delete All)?", client); + menu.AddItem("sm_spyes", Translate(client, "%t", "Yes")); + menu.AddItem("sm_spno", Translate(client, "%t", "No")); + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +public int MenuHandler_DA_Ask(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "sm_spyes")== 0) + { + DeleteAllProps(); + PrintToChat(param1, "[SM] %T", "Successfully deleted all spawned objects", param1); + } + else + { + PrintToChat(param1, "[SM] %T", "Canceled", param1); + } + BuildDeleteMenu(param1); + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public int MenuHandler_Delete(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "sm_spdeleteall")== 0) + { + BuildDeleteAllAskMenu(param1); + PrintToChat(param1, "[SM] %T", "delete all the spawned objects?", param1); + } + else if(strcmp(menucmd, "sm_spdeletelook")== 0) + { + DeleteLookingEntity(param1); + BuildDeleteMenu(param1); + } + else if(strcmp(menucmd, "sm_spdeletelast")== 0) + { + DeleteLastProp(param1); + BuildDeleteMenu(param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +/* +////////////////////////////////////////////////////////////////////////////| + E D I T M E N U | +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| +*/ + +public void AdminMenu_Edit(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) +{ + if(action == TopMenuAction_DisplayOption) + { + Format(buffer, maxlength, Translate(param, "%t", "Edit Object")); + } + else if(action == TopMenuAction_SelectOption) + { + BuildEditPropMenu(param); + } +} + +/* +////////////////////////////////////////////////////////////////////////////| + S P A W N M E N U | +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| +*/ + +public void AdminMenu_Spawn(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) +{ + if(action == TopMenuAction_DisplayOption) + { + Format(buffer, maxlength, Translate(param, "%t", "Spawn Objects")); + } + else if(action == TopMenuAction_SelectOption) + { + ConVar cheats = FindConVar("sm_cheats"); + if(cheats != null && !cheats.BoolValue) { + ReplyToCommand(param, "Set sm_cheats to 1 to use the prop spawner"); + return; + } + BuildSpawnMenu(param); + } +} + +Menu BuildSpawnMenu(int client) +{ + Menu menu = new Menu(MenuHandler_Spawn); + menu.SetTitle("%T", "Select the spawn method", client); + + if(g_cvarPhysics.BoolValue) + { + menu.AddItem("sm_spawnpc", Translate(client, "%t", "Spawn Physics On Cursor")); + menu.AddItem("sm_spawnpo", Translate(client, "%t", "Spawn Physics On Origin")); + } + if(g_cvarDynamic.BoolValue) + { + menu.AddItem("sm_spawndc", Translate(client, "%t", "Spawn Non-solid On Cursor")); + menu.AddItem("sm_spawndo", Translate(client, "%t", "Spawn Non-solid On Origin")); + } + if(g_cvarStatic.BoolValue) + { + menu.AddItem("sm_spawnsc", Translate(client, "%t", "Spawn Solid On Cursor")); + menu.AddItem("sm_spawnso", Translate(client, "%t", "Spawn Solid On Origin")); + } + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +public int MenuHandler_Spawn(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "sm_spawnpc")== 0) + { + BuildPhysicsCursorMenu(param1); + } + else if(strcmp(menucmd, "sm_spawnpo")== 0) + { + BuildPhysicsPositionMenu(param1); + } + else if(strcmp(menucmd, "sm_spawndc")== 0) + { + BuildDynamicCursorMenu(param1); + } + else if(strcmp(menucmd, "sm_spawndo")== 0) + { + BuildDynamicPositionMenu(param1); + } + else if(strcmp(menucmd, "sm_spawnsc")== 0) + { + BuildStaticCursorMenu(param1); + } + else if(strcmp(menucmd, "sm_spawnso")== 0) + { + BuildStaticPositionMenu(param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +/* +////////////////////////////////////////////////////////////////////////////| + S A V E M E N U | +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| +*/ + +public void AdminMenu_Save(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) +{ + if(action == TopMenuAction_DisplayOption) + { + Format(buffer, maxlength, Translate(param, "%t", "Save Objects")); + } + else if(action == TopMenuAction_SelectOption) + { + BuildSaveMenu(param); + } +} + +Menu BuildSaveMenu(int client) +{ + Menu menu = new Menu(MenuHandler_Save); + menu.SetTitle("%T", "Select The Save Method", client); + menu.AddItem("sm_spsavestripper", Translate(client, "%t", "Save Stripper File")); + menu.AddItem("sm_spsaverouting", Translate(client, "%t", "Save Routing File")); + menu.AddItem("sm_spsaveplugin", Translate(client, "%t", "Save Spawn Objects File")); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +Menu BuildRoutingMenu(int client) +{ + Menu menu = new Menu(MenuHandler_PathDiff); + menu.SetTitle("%T", "Select Path Difficulty", client); + menu.AddItem("sm_speasy", Translate(client, "%t", "Easy Path")); + menu.AddItem("sm_spmedium", Translate(client, "%t", "Medium Path")); + menu.AddItem("sm_sphard", Translate(client, "%t", "Hard Path")); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +public int MenuHandler_PathDiff(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "sm_speasy")== 0) + { + SaveRoutingPath(param1, RouteType_Easy); + } + else if(strcmp(menucmd, "sm_spmedium")== 0) + { + SaveRoutingPath(param1, RouteType_Medium); + } + else if(strcmp(menucmd, "sm_sphard")== 0) + { + SaveRoutingPath(param1, RouteType_Hard); + } + BuildSaveMenu(param1); + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public int MenuHandler_Save(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "sm_spsavestripper")== 0) + { + SaveMapStripper(param1); + BuildSaveMenu(param1); + } + else if(strcmp(menucmd, "sm_spsaverouting")== 0) + { + BuildRoutingMenu(param1); + } + else if(strcmp(menucmd, "sm_spsaveplugin")== 0) + { + SavePluginProps(param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +/* +////////////////////////////////////////////////////////////////////////////| + L O A D M E N U | +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| +*/ + +public void AdminMenu_Load(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) +{ + if(action == TopMenuAction_DisplayOption) + { + Format(buffer, maxlength, Translate(param, "%t", "Load Objects")); + } + else if(action == TopMenuAction_SelectOption) + { + BuildLoadAskMenu(param); + PrintToChat(param, "[SM] %T", "load the map data cache?", param); + } +} + +Menu BuildLoadAskMenu(int client) +{ + Menu menu = new Menu(MenuHandler_Load_Ask); + menu.SetTitle("%T", "Are you sure?", client); + menu.AddItem("sm_spyes", Translate(client, "%t", "Yes")); + menu.AddItem("sm_spno", Translate(client, "%t", "No")); + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +Menu BuildLoadPropsMenu(int client) +{ + Menu menu = new Menu(MenuHandler_Load_Props); + menu.SetTitle("%T", "Choose a map number please", client); + char buffer[16]; + char buffer2[16]; + for(int i=1; i <= MAX_PATHS; i++) + { + Format(buffer, sizeof(buffer), "map%i", i); + Format(buffer2, sizeof(buffer2), "Map %i", i); + menu.AddItem(buffer, buffer2); + } + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +public int MenuHandler_Load_Props(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + ReplaceString(menucmd, sizeof(menucmd), "map", "", false); + int number = StringToInt(menucmd); + LoadPluginProps(param1, number); + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public int MenuHandler_Load_Ask(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "sm_spyes")== 0) + { + BuildLoadPropsMenu(param1); + } + else + { + PrintToChat(param1, "[SM] %T", "Canceled", param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +/* +////////////////////////////////////////////////////////////////////////////| + Build Secondary Menus | +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| +*/ +Menu BuildPhysicsCursorMenu(int client) +{ + Menu menu = new Menu(MenuHandler_PhysicsCursor); + CheckSecondaryMenuCategories(menu, client); +} + +Menu BuildPhysicsPositionMenu(int client) +{ + Menu menu = new Menu(MenuHandler_PhysicsPosition); + CheckSecondaryMenuCategories(menu, client); +} + +Menu BuildDynamicCursorMenu(int client) +{ + Menu menu = new Menu(MenuHandler_DynamicCursor); + CheckSecondaryMenuCategories(menu, client); +} + +Menu BuildDynamicPositionMenu(int client) +{ + Menu menu = new Menu(MenuHandler_DynamicPosition); + CheckSecondaryMenuCategories(menu, client); +} +Menu BuildStaticCursorMenu(int client) +{ + Menu menu = new Menu(MenuHandler_StaticCursor); + CheckSecondaryMenuCategories(menu, client); +} +Menu BuildStaticPositionMenu(int client) +{ + Menu menu = new Menu(MenuHandler_StaticPosition); + CheckSecondaryMenuCategories(menu, client); +} + +Menu CheckSecondaryMenuCategories(Menu menu, int client) +{ + if(g_cvarVehicles.BoolValue) + { + menu.AddItem("vehicles", Translate(client, "%t", "Vehicles")); + } + if(g_cvarFoliage.BoolValue) + { + menu.AddItem("foliage", Translate(client, "%t", "Foliage")); + } + if(g_cvarFurniture.BoolValue) + { + menu.AddItem("furniture", Translate(client, "%t", "Furniture")); + } + if(g_cvarFurnishings.BoolValue) + { + menu.AddItem("furnishings", Translate(client, "%t", "Furnishings")); + } + if(g_cvarAppliances.BoolValue) + { + menu.AddItem("appliances", Translate(client, "%t", "Appliances")); + } + if(g_cvarBuildings.BoolValue) + { + menu.AddItem("buildings", Translate(client, "%t", "Buildings")); + } + if(g_cvarScaffolding.BoolValue) + { + menu.AddItem("scaffolding", Translate(client, "%t", "Scaffolding")); + } + if(g_cvarDoors.BoolValue) + { + menu.AddItem("doors", Translate(client, "%t", "Doors")); + } + if(g_cvarWindows.BoolValue) + { + menu.AddItem("windows", Translate(client, "%t", "Windows")); + } + if(g_cvarLights.BoolValue) + { + menu.AddItem("lights", Translate(client, "%t", "Lights")); + } + if(g_cvarSigns.BoolValue) + { + menu.AddItem("signs", Translate(client, "%t", "Signs")); + } + if(g_cvarFencing.BoolValue) + { + menu.AddItem("fencing", Translate(client, "%t", "Fencing")); + } + if(g_cvarRailing.BoolValue) + { + menu.AddItem("railing", Translate(client, "%t", "Railing")); + } + if(g_cvarStairs.BoolValue) + { + menu.AddItem("stairs", Translate(client, "%t", "Stairs")); + } + if(g_cvarOffice.BoolValue) + { + menu.AddItem("office", Translate(client, "%t", "Office")); + } + if(g_cvarStreets.BoolValue) + { + menu.AddItem("streets", Translate(client, "%t", "Streets")); + } + if(g_cvarFairgrounds.BoolValue) + { + menu.AddItem("fairgrounds", Translate(client, "%t", "Fairgrounds")); + } + if(g_cvarMall.BoolValue) + { + menu.AddItem("mall", Translate(client, "%t", "Mall")); + } + if(g_cvarConstruction.BoolValue) + { + menu.AddItem("construction", Translate(client, "%t", "Construction")); + } + if(g_cvarGeneralMisc.BoolValue) + { + menu.AddItem("generalmisc", Translate(client, "%t", "GeneralMisc")); + } + if(g_cvarExteriorMisc.BoolValue) + { + menu.AddItem("exteriormisc", Translate(client, "%t", "ExteriorMisc")); + } + if(g_cvarInteriorMisc.BoolValue) + { + menu.AddItem("interiormisc", Translate(client, "%t", "InteriorMisc")); + } + if(g_cvarDebris.BoolValue) + { + menu.AddItem("debris", Translate(client, "%t", "Debris")); + } + if(g_cvarJunk.BoolValue) + { + menu.AddItem("junk", Translate(client, "%t", "Junk")); + } + if(g_cvarPipes.BoolValue) + { + menu.AddItem("pipes", Translate(client, "%t", "Pipes")); + } + if(g_cvarBodiesGeneric.BoolValue) + { + menu.AddItem("bodiesgeneric", Translate(client, "%t", "BodiesGeneric")); + } + if(g_cvarBodiesSwamp.BoolValue) + { + menu.AddItem("bodiesswamp", Translate(client, "%t", "BodiesSwamp")); + } + if(g_cvarBodiesSugarMill.BoolValue) + { + menu.AddItem("BodiesSugarMill", Translate(client, "%t", "BodiesSugarMill")); + } + if(g_cvarBodiesCemetary.BoolValue) + { + menu.AddItem("bodiescemetary", Translate(client, "%t", "BodiesCemetary")); + } + if(g_cvarInfected.BoolValue) + { + menu.AddItem("infected", Translate(client, "%t", "Infected")); + } + if(g_cvarSkybox.BoolValue) + { + menu.AddItem("skybox", Translate(client, "%t", "Skybox")); + } + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +Menu BuildEditPropMenu(int client) +{ + Menu menu = new Menu(MenuHandler_EditProp); + menu.SetTitle("%T", "Select an action:", client); + menu.AddItem("rotate", Translate(client, "%t", "Rotate")); + menu.AddItem("move", Translate(client, "%t", "Move")); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +public int MenuHandler_PhysicsCursor(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + g_iCategory[param1] = 1; + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "vehicles")== 0) + { + DisplayVehiclesMenu(param1); + } + else if(strcmp(menucmd, "foliage")== 0) + { + DisplayFoliageMenu(param1); + } + else if(strcmp(menucmd, "furniture")== 0) + { + DisplayFurnitureMenu(param1); + } + else if(strcmp(menucmd, "furnishings")== 0) + { + DisplayFurnishingsMenu(param1); + } + else if(strcmp(menucmd, "appliances")== 0) + { + DisplayAppliancesMenu(param1); + } + else if(strcmp(menucmd, "buildings")== 0) + { + DisplayBuildingsMenu(param1); + } + else if(strcmp(menucmd, "scaffolding")== 0) + { + DisplayScaffoldingMenu(param1); + } + else if(strcmp(menucmd, "doors")== 0) + { + DisplayDoorsMenu(param1); + } + else if(strcmp(menucmd, "windows")== 0) + { + DisplayWindowsMenu(param1); + } + else if(strcmp(menucmd, "lights")== 0) + { + DisplayLightsMenu(param1); + } + else if(strcmp(menucmd, "signs")== 0) + { + DisplaySignsMenu(param1); + } + else if(strcmp(menucmd, "fencing")== 0) + { + DisplayFencingMenu(param1); + } + else if(strcmp(menucmd, "railing")== 0) + { + DisplayRailingMenu(param1); + } + else if(strcmp(menucmd, "stairs")== 0) + { + DisplayStairsMenu(param1); + } + else if(strcmp(menucmd, "office")== 0) + { + DisplayOfficeMenu(param1); + } + else if(strcmp(menucmd, "streets")== 0) + { + DisplayStreetsMenu(param1); + } + else if(strcmp(menucmd, "fairgrounds")== 0) + { + DisplayFairgroundsMenu(param1); + } + else if(strcmp(menucmd, "mall")== 0) + { + DisplayMallMenu(param1); + } + else if(strcmp(menucmd, "construction")== 0) + { + DisplayConstructionMenu(param1); + } + else if(strcmp(menucmd, "generalmisc")== 0) + { + DisplayGeneralMiscMenu(param1); + } + else if(strcmp(menucmd, "exteriormisc")== 0) + { + DisplayExteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "interiormisc")== 0) + { + DisplayInteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "debris")== 0) + { + DisplayDebrisMenu(param1); + } + else if(strcmp(menucmd, "junk")== 0) + { + DisplayJunkMenu(param1); + } + else if(strcmp(menucmd, "pipes")== 0) + { + DisplayPipesMenu(param1); + } + else if(strcmp(menucmd, "bodiesgeneric")== 0) + { + DisplayBodiesGenericMenu(param1); + } + else if(strcmp(menucmd, "bodiesswamp")== 0) + { + DisplayBodiesSwampMenu(param1); + } + else if(strcmp(menucmd, "BodiesSugarMill")== 0) + { + DisplayBodiesSugarMill(param1); + } + else if(strcmp(menucmd, "bodiescemetary")== 0) + { + DisplayBodiesCemetaryMenu(param1); + } + else if(strcmp(menucmd, "infected")== 0) + { + DisplayInfectedMenu(param1); + } + else if(strcmp(menucmd, "skybox")== 0) + { + DisplaySkyboxMenu(param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public int MenuHandler_PhysicsPosition(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + g_iCategory[param1] = 2; + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "vehicles")== 0) + { + DisplayVehiclesMenu(param1); + } + else if(strcmp(menucmd, "foliage")== 0) + { + DisplayFoliageMenu(param1); + } + else if(strcmp(menucmd, "furniture")== 0) + { + DisplayFurnitureMenu(param1); + } + else if(strcmp(menucmd, "furnishings")== 0) + { + DisplayFurnishingsMenu(param1); + } + else if(strcmp(menucmd, "appliances")== 0) + { + DisplayAppliancesMenu(param1); + } + else if(strcmp(menucmd, "buildings")== 0) + { + DisplayBuildingsMenu(param1); + } + else if(strcmp(menucmd, "scaffolding")== 0) + { + DisplayScaffoldingMenu(param1); + } + else if(strcmp(menucmd, "doors")== 0) + { + DisplayDoorsMenu(param1); + } + else if(strcmp(menucmd, "windows")== 0) + { + DisplayWindowsMenu(param1); + } + else if(strcmp(menucmd, "lights")== 0) + { + DisplayLightsMenu(param1); + } + else if(strcmp(menucmd, "signs")== 0) + { + DisplaySignsMenu(param1); + } + else if(strcmp(menucmd, "fencing")== 0) + { + DisplayFencingMenu(param1); + } + else if(strcmp(menucmd, "railing")== 0) + { + DisplayRailingMenu(param1); + } + else if(strcmp(menucmd, "stairs")== 0) + { + DisplayStairsMenu(param1); + } + else if(strcmp(menucmd, "office")== 0) + { + DisplayOfficeMenu(param1); + } + else if(strcmp(menucmd, "streets")== 0) + { + DisplayStreetsMenu(param1); + } + else if(strcmp(menucmd, "fairgrounds")== 0) + { + DisplayFairgroundsMenu(param1); + } + else if(strcmp(menucmd, "mall")== 0) + { + DisplayMallMenu(param1); + } + else if(strcmp(menucmd, "construction")== 0) + { + DisplayConstructionMenu(param1); + } + else if(strcmp(menucmd, "generalmisc")== 0) + { + DisplayGeneralMiscMenu(param1); + } + else if(strcmp(menucmd, "exteriormisc")== 0) + { + DisplayExteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "interiormisc")== 0) + { + DisplayInteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "debris")== 0) + { + DisplayDebrisMenu(param1); + } + else if(strcmp(menucmd, "junk")== 0) + { + DisplayJunkMenu(param1); + } + else if(strcmp(menucmd, "pipes")== 0) + { + DisplayPipesMenu(param1); + } + else if(strcmp(menucmd, "bodiesgeneric")== 0) + { + DisplayBodiesGenericMenu(param1); + } + else if(strcmp(menucmd, "bodiesswamp")== 0) + { + DisplayBodiesSwampMenu(param1); + } + else if(strcmp(menucmd, "BodiesSugarMill")== 0) + { + DisplayBodiesSugarMill(param1); + } + else if(strcmp(menucmd, "bodiescemetary")== 0) + { + DisplayBodiesCemetaryMenu(param1); + } + else if(strcmp(menucmd, "infected")== 0) + { + DisplayInfectedMenu(param1); + } + else if(strcmp(menucmd, "skybox")== 0) + { + DisplaySkyboxMenu(param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public int MenuHandler_DynamicCursor(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + g_iCategory[param1] = 3; + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "vehicles")== 0) + { + DisplayVehiclesMenu(param1); + } + else if(strcmp(menucmd, "foliage")== 0) + { + DisplayFoliageMenu(param1); + } + else if(strcmp(menucmd, "furniture")== 0) + { + DisplayFurnitureMenu(param1); + } + else if(strcmp(menucmd, "furnishings")== 0) + { + DisplayFurnishingsMenu(param1); + } + else if(strcmp(menucmd, "appliances")== 0) + { + DisplayAppliancesMenu(param1); + } + else if(strcmp(menucmd, "buildings")== 0) + { + DisplayBuildingsMenu(param1); + } + else if(strcmp(menucmd, "scaffolding")== 0) + { + DisplayScaffoldingMenu(param1); + } + else if(strcmp(menucmd, "doors")== 0) + { + DisplayDoorsMenu(param1); + } + else if(strcmp(menucmd, "windows")== 0) + { + DisplayWindowsMenu(param1); + } + else if(strcmp(menucmd, "lights")== 0) + { + DisplayLightsMenu(param1); + } + else if(strcmp(menucmd, "signs")== 0) + { + DisplaySignsMenu(param1); + } + else if(strcmp(menucmd, "fencing")== 0) + { + DisplayFencingMenu(param1); + } + else if(strcmp(menucmd, "railing")== 0) + { + DisplayRailingMenu(param1); + } + else if(strcmp(menucmd, "stairs")== 0) + { + DisplayStairsMenu(param1); + } + else if(strcmp(menucmd, "office")== 0) + { + DisplayOfficeMenu(param1); + } + else if(strcmp(menucmd, "streets")== 0) + { + DisplayStreetsMenu(param1); + } + else if(strcmp(menucmd, "fairgrounds")== 0) + { + DisplayFairgroundsMenu(param1); + } + else if(strcmp(menucmd, "mall")== 0) + { + DisplayMallMenu(param1); + } + else if(strcmp(menucmd, "construction")== 0) + { + DisplayConstructionMenu(param1); + } + else if(strcmp(menucmd, "generalmisc")== 0) + { + DisplayGeneralMiscMenu(param1); + } + else if(strcmp(menucmd, "exteriormisc")== 0) + { + DisplayExteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "interiormisc")== 0) + { + DisplayInteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "debris")== 0) + { + DisplayDebrisMenu(param1); + } + else if(strcmp(menucmd, "junk")== 0) + { + DisplayJunkMenu(param1); + } + else if(strcmp(menucmd, "pipes")== 0) + { + DisplayPipesMenu(param1); + } + else if(strcmp(menucmd, "bodiesgeneric")== 0) + { + DisplayBodiesGenericMenu(param1); + } + else if(strcmp(menucmd, "bodiesswamp")== 0) + { + DisplayBodiesSwampMenu(param1); + } + else if(strcmp(menucmd, "BodiesSugarMill")== 0) + { + DisplayBodiesSugarMill(param1); + } + else if(strcmp(menucmd, "bodiescemetary")== 0) + { + DisplayBodiesCemetaryMenu(param1); + } + else if(strcmp(menucmd, "infected")== 0) + { + DisplayInfectedMenu(param1); + } + else if(strcmp(menucmd, "skybox")== 0) + { + DisplaySkyboxMenu(param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public int MenuHandler_DynamicPosition(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + g_iCategory[param1] = 4; + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "vehicles")== 0) + { + DisplayVehiclesMenu(param1); + } + else if(strcmp(menucmd, "foliage")== 0) + { + DisplayFoliageMenu(param1); + } + else if(strcmp(menucmd, "furniture")== 0) + { + DisplayFurnitureMenu(param1); + } + else if(strcmp(menucmd, "furnishings")== 0) + { + DisplayFurnishingsMenu(param1); + } + else if(strcmp(menucmd, "appliances")== 0) + { + DisplayAppliancesMenu(param1); + } + else if(strcmp(menucmd, "buildings")== 0) + { + DisplayBuildingsMenu(param1); + } + else if(strcmp(menucmd, "scaffolding")== 0) + { + DisplayScaffoldingMenu(param1); + } + else if(strcmp(menucmd, "doors")== 0) + { + DisplayDoorsMenu(param1); + } + else if(strcmp(menucmd, "windows")== 0) + { + DisplayWindowsMenu(param1); + } + else if(strcmp(menucmd, "lights")== 0) + { + DisplayLightsMenu(param1); + } + else if(strcmp(menucmd, "signs")== 0) + { + DisplaySignsMenu(param1); + } + else if(strcmp(menucmd, "fencing")== 0) + { + DisplayFencingMenu(param1); + } + else if(strcmp(menucmd, "railing")== 0) + { + DisplayRailingMenu(param1); + } + else if(strcmp(menucmd, "stairs")== 0) + { + DisplayStairsMenu(param1); + } + else if(strcmp(menucmd, "office")== 0) + { + DisplayOfficeMenu(param1); + } + else if(strcmp(menucmd, "streets")== 0) + { + DisplayStreetsMenu(param1); + } + else if(strcmp(menucmd, "fairgrounds")== 0) + { + DisplayFairgroundsMenu(param1); + } + else if(strcmp(menucmd, "mall")== 0) + { + DisplayMallMenu(param1); + } + else if(strcmp(menucmd, "construction")== 0) + { + DisplayConstructionMenu(param1); + } + else if(strcmp(menucmd, "generalmisc")== 0) + { + DisplayGeneralMiscMenu(param1); + } + else if(strcmp(menucmd, "exteriormisc")== 0) + { + DisplayExteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "interiormisc")== 0) + { + DisplayInteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "debris")== 0) + { + DisplayDebrisMenu(param1); + } + else if(strcmp(menucmd, "junk")== 0) + { + DisplayJunkMenu(param1); + } + else if(strcmp(menucmd, "pipes")== 0) + { + DisplayPipesMenu(param1); + } + else if(strcmp(menucmd, "bodiesgeneric")== 0) + { + DisplayBodiesGenericMenu(param1); + } + else if(strcmp(menucmd, "bodiesswamp")== 0) + { + DisplayBodiesSwampMenu(param1); + } + else if(strcmp(menucmd, "BodiesSugarMill")== 0) + { + DisplayBodiesSugarMill(param1); + } + else if(strcmp(menucmd, "bodiescemetary")== 0) + { + DisplayBodiesCemetaryMenu(param1); + } + else if(strcmp(menucmd, "infected")== 0) + { + DisplayInfectedMenu(param1); + } + else if(strcmp(menucmd, "skybox")== 0) + { + DisplaySkyboxMenu(param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public int MenuHandler_StaticCursor(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + g_iCategory[param1] = 5; + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "vehicles")== 0) + { + DisplayVehiclesMenu(param1); + } + else if(strcmp(menucmd, "foliage")== 0) + { + DisplayFoliageMenu(param1); + } + else if(strcmp(menucmd, "furniture")== 0) + { + DisplayFurnitureMenu(param1); + } + else if(strcmp(menucmd, "furnishings")== 0) + { + DisplayFurnishingsMenu(param1); + } + else if(strcmp(menucmd, "appliances")== 0) + { + DisplayAppliancesMenu(param1); + } + else if(strcmp(menucmd, "buildings")== 0) + { + DisplayBuildingsMenu(param1); + } + else if(strcmp(menucmd, "scaffolding")== 0) + { + DisplayScaffoldingMenu(param1); + } + else if(strcmp(menucmd, "doors")== 0) + { + DisplayDoorsMenu(param1); + } + else if(strcmp(menucmd, "windows")== 0) + { + DisplayWindowsMenu(param1); + } + else if(strcmp(menucmd, "lights")== 0) + { + DisplayLightsMenu(param1); + } + else if(strcmp(menucmd, "signs")== 0) + { + DisplaySignsMenu(param1); + } + else if(strcmp(menucmd, "fencing")== 0) + { + DisplayFencingMenu(param1); + } + else if(strcmp(menucmd, "railing")== 0) + { + DisplayRailingMenu(param1); + } + else if(strcmp(menucmd, "stairs")== 0) + { + DisplayStairsMenu(param1); + } + else if(strcmp(menucmd, "office")== 0) + { + DisplayOfficeMenu(param1); + } + else if(strcmp(menucmd, "streets")== 0) + { + DisplayStreetsMenu(param1); + } + else if(strcmp(menucmd, "fairgrounds")== 0) + { + DisplayFairgroundsMenu(param1); + } + else if(strcmp(menucmd, "mall")== 0) + { + DisplayMallMenu(param1); + } + else if(strcmp(menucmd, "construction")== 0) + { + DisplayConstructionMenu(param1); + } + else if(strcmp(menucmd, "generalmisc")== 0) + { + DisplayGeneralMiscMenu(param1); + } + else if(strcmp(menucmd, "exteriormisc")== 0) + { + DisplayExteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "interiormisc")== 0) + { + DisplayInteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "debris")== 0) + { + DisplayDebrisMenu(param1); + } + else if(strcmp(menucmd, "junk")== 0) + { + DisplayJunkMenu(param1); + } + else if(strcmp(menucmd, "pipes")== 0) + { + DisplayPipesMenu(param1); + } + else if(strcmp(menucmd, "bodiesgeneric")== 0) + { + DisplayBodiesGenericMenu(param1); + } + else if(strcmp(menucmd, "bodiesswamp")== 0) + { + DisplayBodiesSwampMenu(param1); + } + else if(strcmp(menucmd, "BodiesSugarMill")== 0) + { + DisplayBodiesSugarMill(param1); + } + else if(strcmp(menucmd, "bodiescemetary")== 0) + { + DisplayBodiesCemetaryMenu(param1); + } + else if(strcmp(menucmd, "infected")== 0) + { + DisplayInfectedMenu(param1); + } + else if(strcmp(menucmd, "skybox")== 0) + { + DisplaySkyboxMenu(param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public int MenuHandler_StaticPosition(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + g_iCategory[param1] = 6; + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "vehicles")== 0) + { + DisplayVehiclesMenu(param1); + } + else if(strcmp(menucmd, "foliage")== 0) + { + DisplayFoliageMenu(param1); + } + else if(strcmp(menucmd, "furniture")== 0) + { + DisplayFurnitureMenu(param1); + } + else if(strcmp(menucmd, "furnishings")== 0) + { + DisplayFurnishingsMenu(param1); + } + else if(strcmp(menucmd, "appliances")== 0) + { + DisplayAppliancesMenu(param1); + } + else if(strcmp(menucmd, "buildings")== 0) + { + DisplayBuildingsMenu(param1); + } + else if(strcmp(menucmd, "scaffolding")== 0) + { + DisplayScaffoldingMenu(param1); + } + else if(strcmp(menucmd, "doors")== 0) + { + DisplayDoorsMenu(param1); + } + else if(strcmp(menucmd, "windows")== 0) + { + DisplayWindowsMenu(param1); + } + else if(strcmp(menucmd, "lights")== 0) + { + DisplayLightsMenu(param1); + } + else if(strcmp(menucmd, "signs")== 0) + { + DisplaySignsMenu(param1); + } + else if(strcmp(menucmd, "fencing")== 0) + { + DisplayFencingMenu(param1); + } + else if(strcmp(menucmd, "railing")== 0) + { + DisplayRailingMenu(param1); + } + else if(strcmp(menucmd, "stairs")== 0) + { + DisplayStairsMenu(param1); + } + else if(strcmp(menucmd, "office")== 0) + { + DisplayOfficeMenu(param1); + } + else if(strcmp(menucmd, "streets")== 0) + { + DisplayStreetsMenu(param1); + } + else if(strcmp(menucmd, "fairgrounds")== 0) + { + DisplayFairgroundsMenu(param1); + } + else if(strcmp(menucmd, "mall")== 0) + { + DisplayMallMenu(param1); + } + else if(strcmp(menucmd, "construction")== 0) + { + DisplayConstructionMenu(param1); + } + else if(strcmp(menucmd, "generalmisc")== 0) + { + DisplayGeneralMiscMenu(param1); + } + else if(strcmp(menucmd, "exteriormisc")== 0) + { + DisplayExteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "interiormisc")== 0) + { + DisplayInteriorMiscMenu(param1); + } + else if(strcmp(menucmd, "debris")== 0) + { + DisplayDebrisMenu(param1); + } + else if(strcmp(menucmd, "junk")== 0) + { + DisplayJunkMenu(param1); + } + else if(strcmp(menucmd, "pipes")== 0) + { + DisplayPipesMenu(param1); + } + else if(strcmp(menucmd, "bodiesgeneric")== 0) + { + DisplayBodiesGenericMenu(param1); + } + else if(strcmp(menucmd, "bodiesswamp")== 0) + { + DisplayBodiesSwampMenu(param1); + } + else if(strcmp(menucmd, "BodiesSugarMill")== 0) + { + DisplayBodiesSugarMill(param1); + } + else if(strcmp(menucmd, "bodiescemetary")== 0) + { + DisplayBodiesCemetaryMenu(param1); + } + else if(strcmp(menucmd, "infected")== 0) + { + DisplayInfectedMenu(param1); + } + else if(strcmp(menucmd, "skybox")== 0) + { + DisplaySkyboxMenu(param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public int MenuHandler_EditProp(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "rotate")== 0) + { + DisplayRotateMenu(param1); + } + else if(strcmp(menucmd, "move")== 0) + { + DisplayMoveMenu(param1); + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack && g_TopMenuHandle != null) + { + g_TopMenuHandle.Display(param1, TopMenuPosition_LastCategory); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +Menu DisplayVehiclesMenu(int client) +{ + g_iSubCategory[client] = 1; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Vehicles", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iVehiclesMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayFoliageMenu(int client) +{ + g_iSubCategory[client] = 2; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Foliage", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iFoliageMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayFurnitureMenu(int client) +{ + g_iSubCategory[client] = 3; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Furniture", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iFurnitureMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayFurnishingsMenu(int client) +{ + g_iSubCategory[client] = 4; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Furnishings", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iFurnishingsMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayAppliancesMenu(int client) +{ + g_iSubCategory[client] = 5; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Appliances", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iAppliancesMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayBuildingsMenu(int client) +{ + g_iSubCategory[client] = 6; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Buildings", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iBuildingsMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayScaffoldingMenu(int client) +{ + g_iSubCategory[client] = 7; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Scaffolding", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iScaffoldingMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayDoorsMenu(int client) +{ + g_iSubCategory[client] = 8; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Doors", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iDoorsMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayWindowsMenu(int client) +{ + g_iSubCategory[client] = 9; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Windows", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iWindowsMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayLightsMenu(int client) +{ + g_iSubCategory[client] = 10; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Lights", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iLightsMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplaySignsMenu(int client) +{ + g_iSubCategory[client] = 11; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Signs", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iSignssMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayFencingMenu(int client) +{ + g_iSubCategory[client] = 12; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Fencing", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iFencingMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayRailingMenu(int client) +{ + g_iSubCategory[client] = 13; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Railing", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iRailingMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayStairsMenu(int client) +{ + g_iSubCategory[client] = 14; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Stairs", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iStairsMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayOfficeMenu(int client) +{ + g_iSubCategory[client] = 15; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Office", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iOfficeMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayStreetsMenu(int client) +{ + g_iSubCategory[client] = 16; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Streets", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iStreetsMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayFairgroundsMenu(int client) +{ + g_iSubCategory[client] = 17; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Fairgrounds", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iFairgroundsMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayMallMenu(int client) +{ + g_iSubCategory[client] = 18; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Mall", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iMallMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayConstructionMenu(int client) +{ + g_iSubCategory[client] = 19; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Construction", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iConstructionMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayGeneralMiscMenu(int client) +{ + g_iSubCategory[client] = 20; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "GeneralMisc", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iGeneralMiscMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayExteriorMiscMenu(int client) +{ + g_iSubCategory[client] = 21; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "ExteriorMisc", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iExteriorMiscMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayInteriorMiscMenu(int client) +{ + g_iSubCategory[client] = 22; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "InteriorMisc", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iInteriorMiscMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayDebrisMenu(int client) +{ + g_iSubCategory[client] = 23; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Debris", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iDebrisMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayJunkMenu(int client) +{ + g_iSubCategory[client] = 24; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Junk", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iJunkMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayPipesMenu(int client) +{ + g_iSubCategory[client] = 1; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Pipes", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iPipesMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayBodiesGenericMenu(int client) +{ + g_iSubCategory[client] = 25; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "BodiesGeneric", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iBodiesGenericMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayBodiesSwampMenu(int client) +{ + g_iSubCategory[client] = 26; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "BodiesSwamp", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iBodiesSwampMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayBodiesSugarMill(int client) +{ + g_iSubCategory[client] = 27; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "BodiesSugarMill", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iBodiesSugarMillMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayBodiesCemetaryMenu(int client) +{ + g_iSubCategory[client] = 28; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "BodiesCemetary", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iBodiesCemetaryMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayInfectedMenu(int client) +{ + g_iSubCategory[client] = 29; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Infected", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iInfectedMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplaySkyboxMenu(int client) +{ + g_iSubCategory[client] = 1; + Menu menu = new Menu(MenuHandler_DoAction); + SetFileCategory(menu, client); + menu.SetTitle("%T", "Skybox", client); + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iSkyboxMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu SetFileCategory(Menu menu, int client) +{ + File file; + char FileName[256]; + char ItemModel[256]; + char ItemTag[256]; + char buffer[256]; + BuildPath(Path_SM, FileName, sizeof(FileName), "data/l4d2_spawn_props_models.txt"); + int len; + if(!FileExists(FileName)) + { + SetFailState("Unable to find the l4d2_spawn_props_models.txt file"); + } + file = OpenFile(FileName, "r"); + if(file == null) + { + SetFailState("Error opening the models file"); + } + g_iFileCategory[client] = 0; + while(file.ReadLine(buffer, sizeof(buffer))) + { + len = strlen(buffer); + if (buffer[len-1] == 'n') + { + buffer[--len] = '0'; + } + if(StrContains(buffer, "//Category Vehicles") >= 0) + { + g_iFileCategory[client] = 1; + continue; + } + else if(StrContains(buffer, "//Category Foliage") >= 0) + { + g_iFileCategory[client] = 2; + continue; + } + else if(StrContains(buffer, "//Category Furniture") >= 0) + { + g_iFileCategory[client] = 3; + continue; + } + if(StrContains(buffer, "//Category Furnishings") >= 0) + { + g_iFileCategory[client] = 4; + continue; + } + else if(StrContains(buffer, "//Category Appliances") >= 0) + { + g_iFileCategory[client] = 5; + continue; + } + if(StrContains(buffer, "//Category Buildings") >= 0) + { + g_iFileCategory[client] = 6; + continue; + } + if(StrContains(buffer, "//Category Scaffolding") >= 0) + { + g_iFileCategory[client] = 7; + continue; + } + if(StrContains(buffer, "//Category Doors") >= 0) + { + g_iFileCategory[client] = 8; + continue; + } + if(StrContains(buffer, "//Category Windows") >= 0) + { + g_iFileCategory[client] = 9; + continue; + } + if(StrContains(buffer, "//Category Lights") >= 0) + { + g_iFileCategory[client] = 10; + continue; + } + else if(StrContains(buffer, "//Category Signs") >= 0) + { + g_iFileCategory[client] = 11; + continue; + } + if(StrContains(buffer, "//Category Fencing") >= 0) + { + g_iFileCategory[client] = 12; + continue; + } + if(StrContains(buffer, "//Category Railing") >= 0) + { + g_iFileCategory[client] = 13; + continue; + } + if(StrContains(buffer, "//Category Stairs") >= 0) + { + g_iFileCategory[client] = 14; + continue; + } + else if(StrContains(buffer, "//Category Office") >= 0) + { + g_iFileCategory[client] = 15; + continue; + } + else if(StrContains(buffer, "//Category Streets") >= 0) + { + g_iFileCategory[client] = 16; + continue; + } + else if(StrContains(buffer, "//Category Fairgrounds") >= 0) + { + g_iFileCategory[client] = 17; + continue; + } + else if(StrContains(buffer, "//Category Mall") >= 0) + { + g_iFileCategory[client] = 18; + continue; + } + else if(StrContains(buffer, "//Category Construction") >= 0) + { + g_iFileCategory[client] = 19; + continue; + } + else if(StrContains(buffer, "//Category GeneralMisc") >= 0) + { + g_iFileCategory[client] = 20; + continue; + } + else if(StrContains(buffer, "//Category ExteriorMisc") >= 0) + { + g_iFileCategory[client] = 21; + continue; + } + else if(StrContains(buffer, "//Category InteriorMisc") >= 0) + { + g_iFileCategory[client] = 22; + continue; + } + else if(StrContains(buffer, "//Category Debris") >= 0) + { + g_iFileCategory[client] = 23; + continue; + } + else if(StrContains(buffer, "//Category Junk") >= 0) + { + g_iFileCategory[client] = 24; + continue; + } + else if(StrContains(buffer, "//Category Pipes") >= 0) + { + g_iFileCategory[client] = 25; + continue; + } + else if(StrContains(buffer, "//Category BodiesGeneric") >= 0) + { + g_iFileCategory[client] = 26; + continue; + } + else if(StrContains(buffer, "//Category BodiesSwamp") >= 0) + { + g_iFileCategory[client] = 27; + continue; + } + else if(StrContains(buffer, "//Category BodiesSugarMill") >= 0) + { + g_iFileCategory[client] = 28; + continue; + } + else if(StrContains(buffer, "//Category BodiesCemetary") >= 0) + { + g_iFileCategory[client] = 29; + continue; + } + else if(StrContains(buffer, "//Category Infected") >= 0) + { + g_iFileCategory[client] = 30; + continue; + } + else if(StrContains(buffer, "//Category Skybox") >= 0) + { + g_iFileCategory[client] = 31; + continue; + } + if(strcmp(buffer, "")== 0) + { + continue; + } + if(g_iFileCategory[client] != g_iSubCategory[client]) + { + continue; + } + SplitString(buffer, " TAG-", ItemModel, sizeof(ItemModel)); + + strcopy(ItemTag, sizeof(ItemTag), buffer); + + ReplaceString(ItemTag, sizeof(ItemTag), ItemModel, "", false); + ReplaceString(ItemTag, sizeof(ItemTag), " TAG- ", "", false); + menu.AddItem(ItemModel, ItemTag); + + if(IsEndOfFile(file)) + { + break; + } + } + CloseHandle(file); +} + +Menu DisplayRotateMenu(int client) +{ + g_iMoveCategory[client] = 1; + Menu menu = new Menu(MenuHandler_PropPosition); + menu.SetTitle("%T", "Rotate", client); + menu.AddItem("rotate1x", Translate(client, "%t", "Rotate 1 degree (X axys)")); + menu.AddItem("rotate-1x", Translate(client, "%t", "Back 1 degree (X axys)")); + menu.AddItem("rotate10x", Translate(client, "%t", "Rotate 10 degree (X axys)")); + menu.AddItem("rotate-10x", Translate(client, "%t", "Back 10 degree (X axys)")); + menu.AddItem("rotate15x", Translate(client, "%t", "Rotate 15 degree (X axys)")); + menu.AddItem("rotate-15x", Translate(client, "%t", "Back 15 degree (X axys)")); + menu.AddItem("rotate45x", Translate(client, "%t", "Rotate 45 degree (X axys)")); + menu.AddItem("rotate90x", Translate(client, "%t", "Rotate 90 degree (X axys)")); + menu.AddItem("rotate180x", Translate(client, "%t", "Rotate 180 degree (X axys)")); + menu.AddItem("rotate1y", Translate(client, "%t", "Rotate 1 degree (Y axys)")); + menu.AddItem("rotate-1y", Translate(client, "%t", "Back 1 degree (Y axys)")); + menu.AddItem("rotate10y", Translate(client, "%t", "Rotate 10 degree (Y axys)")); + menu.AddItem("rotate-10y", Translate(client, "%t", "Back 10 degree (Y axys)")); + menu.AddItem("rotate15y", Translate(client, "%t", "Rotate 15 degree (Y axys)")); + menu.AddItem("rotate-15y", Translate(client, "%t", "Back 15 degree (Y axys)")); + menu.AddItem("rotate45y", Translate(client, "%t", "Rotate 45 degree (Y axys)")); + menu.AddItem("rotate90y", Translate(client, "%t", "Rotate 90 degree (Y axys)")); + menu.AddItem("rotate180y", Translate(client, "%t", "Rotate 180 degree (Y axys)")); + menu.AddItem("rotate1z", Translate(client, "%t", "Rotate 1 degree (Z axys)")); + menu.AddItem("rotate-1z", Translate(client, "%t", "Back 1 degree (Z axys)")); + menu.AddItem("rotate10z", Translate(client, "%t", "Rotate 10 degree (Z axys)")); + menu.AddItem("rotate-10z", Translate(client, "%t", "Back 10 degree (Z axys)")); + menu.AddItem("rotate15z", Translate(client, "%t", "Rotate 15 degree (Z axys)")); + menu.AddItem("rotate-15z", Translate(client, "%t", "Back 15 degree (Z axys)")); + menu.AddItem("rotate45z", Translate(client, "%t", "Rotate 45 degree (Z axys)")); + menu.AddItem("rotate90z", Translate(client, "%t", "Rotate 90 degree (Z axys)")); + menu.AddItem("rotate180z", Translate(client, "%t", "Rotate 180 degree (Z axys)")); + + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iRotateMenuPosition[client], MENU_TIME_FOREVER); +} + +Menu DisplayMoveMenu(int client) +{ + g_iMoveCategory[client] = 2; + Menu menu = new Menu(MenuHandler_PropPosition); + menu.SetTitle("%T", "Move", client); + menu.AddItem("moveup1", Translate(client, "%t", "Move Up 1 Unit")); + menu.AddItem("moveup10", Translate(client, "%t", "Move Up 10 Unit")); + menu.AddItem("moveup30", Translate(client, "%t", "Move Up 30 Unit")); + menu.AddItem("movedown1", Translate(client, "%t", "Move Down 1 Unit")); + menu.AddItem("movedown10", Translate(client, "%t", "Move Down 10 Unit")); + menu.AddItem("movedown30", Translate(client, "%t", "Move Down 30 Unit")); + menu.AddItem("moveright1", Translate(client, "%t", "Move Right 1 Unit")); + menu.AddItem("moveright10", Translate(client, "%t", "Move Right 10 Unit")); + menu.AddItem("moveright30", Translate(client, "%t", "Move Right 30 Unit")); + menu.AddItem("moveleft1", Translate(client, "%t", "Move Left 1 Unit")); + menu.AddItem("moveleft10", Translate(client, "%t", "Move Left 10 Unit")); + menu.AddItem("moveleft30", Translate(client, "%t", "Move Left 30 Unit")); + menu.AddItem("moveforward1", Translate(client, "%t", "Move Forward 1 Unit")); + menu.AddItem("moveforward10", Translate(client, "%t", "Move Forward 10 Unit")); + menu.AddItem("moveforward30", Translate(client, "%t", "Move Forward 30 Unit")); + menu.AddItem("movebackward1", Translate(client, "%t", "Move Backward 1 Unit")); + menu.AddItem("movebackward10", Translate(client, "%t", "Move Backward 10 Unit")); + menu.AddItem("movebackward30", Translate(client, "%t", "Move Backward 30 Unit")); + + menu.ExitBackButton = true; + menu.ExitButton = true; + menu.DisplayAt(client, g_iMoveMenuPosition[client], MENU_TIME_FOREVER); +} + +public int MenuHandler_DoAction(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char model[256]; + GetMenuItem(menu, param2, model, sizeof(model)); + if(!IsModelPrecached(model)) + { + PrecacheModel(model); + } + if(g_iCategory[param1] == 1) + { + float VecOrigin[3]; + float VecAngles[3]; + int prop = CreateEntityByName("prop_physics_override"); + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + DispatchSpawn(prop); + GetClientEyePosition(param1, VecOrigin); + GetClientEyeAngles(param1, VecAngles); + + TR_TraceRayFilter(VecOrigin, VecAngles, MASK_OPAQUE, RayType_Infinite, TraceRayDontHitSelf, param1); + if(TR_DidHit(null)) + { + TR_GetEndPosition(VecOrigin); + } + else + { + PrintToChat(param1, "[SM] Vector out of world geometry. Spawning on current position instead"); + } + VecAngles[0] = 0.0; + VecAngles[2] = 0.0; + g_vecLastEntityAngles[param1] = VecAngles; + g_iLastObject[param1] = prop; + DispatchKeyValueVector(prop, "angles", VecAngles); + DispatchSpawn(prop); + g_bSpawned[prop] = true; + g_vecEntityAngles[prop] = VecAngles; + TeleportEntity(prop, VecOrigin, NULL_VECTOR, NULL_VECTOR); + char name[256]; + GetClientName(param1, name, sizeof(name)); + LogSpawn("%s spawned a physics object with model <%s>", name, model); + } + else if(g_iCategory[param1] == 2) + { + float VecOrigin[3]; + float VecAngles[3]; + int prop = CreateEntityByName("prop_physics_override"); + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + DispatchSpawn(prop); + GetClientAbsOrigin(param1, VecOrigin); + GetClientEyeAngles(param1, VecAngles); + VecAngles[0] = 0.0; + VecAngles[2] = 0.0; + g_vecLastEntityAngles[param1] = VecAngles; + g_iLastObject[param1] = prop; + DispatchKeyValueVector(prop, "angles", VecAngles); + DispatchSpawn(prop); + g_bSpawned[prop] = true; + g_vecEntityAngles[prop] = VecAngles; + TeleportEntity(prop, VecOrigin, NULL_VECTOR, NULL_VECTOR); + char name[256]; + GetClientName(param1, name, sizeof(name)); + LogSpawn("%s spawned a physics object with model <%s>", name, model); + } + else if(g_iCategory[param1] == 3) + { + float VecOrigin[3]; + float VecAngles[3]; + int prop = CreateEntityByName("prop_dynamic_override"); + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + DispatchSpawn(prop); + GetClientEyePosition(param1, VecOrigin); + GetClientEyeAngles(param1, VecAngles); + + TR_TraceRayFilter(VecOrigin, VecAngles, MASK_OPAQUE, RayType_Infinite, TraceRayDontHitSelf, param1); + if(TR_DidHit(null)) + { + TR_GetEndPosition(VecOrigin); + } + else + { + PrintToChat(param1, "[SM] Vector out of world geometry. Spawning on current position instead"); + } + VecAngles[0] = 0.0; + VecAngles[2] = 0.0; + g_vecLastEntityAngles[param1] = VecAngles; + g_iLastObject[param1] = prop; + DispatchKeyValueVector(prop, "angles", VecAngles); + DispatchSpawn(prop); + TeleportEntity(prop, VecOrigin, NULL_VECTOR, NULL_VECTOR); + + g_bSpawned[prop] = true; + g_bUnsolid[prop] = true; + g_vecEntityAngles[prop] = VecAngles; + char name[256]; + GetClientName(param1, name, sizeof(name)); + LogSpawn("%s spawned a dynamic object with model <%s>", name, model); + } + else if(g_iCategory[param1] == 4) + { + float VecOrigin[3]; + float VecAngles[3]; + int prop = CreateEntityByName("prop_dynamic_override"); + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + DispatchSpawn(prop); + GetClientAbsOrigin(param1, VecOrigin); + GetClientEyeAngles(param1, VecAngles); + VecAngles[0] = 0.0; + VecAngles[2] = 0.0; + g_vecLastEntityAngles[param1] = VecAngles; + g_iLastObject[param1] = prop; + DispatchKeyValueVector(prop, "angles", VecAngles); + DispatchSpawn(prop); + TeleportEntity(prop, VecOrigin, NULL_VECTOR, NULL_VECTOR); + g_bSpawned[prop] = true; + g_bUnsolid[prop] = true; + g_vecEntityAngles[prop] = VecAngles; + char name[256]; + GetClientName(param1, name, sizeof(name)); + LogSpawn("%s spawned a dynamic object with model <%s>", name, model); + } + else if(g_iCategory[param1] == 5) + { + float VecOrigin[3]; + float VecAngles[3]; + int prop = CreateEntityByName("prop_dynamic_override"); + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + GetClientEyePosition(param1, VecOrigin); + GetClientEyeAngles(param1, VecAngles); + SetEntProp(prop, Prop_Send, "m_nSolidType", 6); + + TR_TraceRayFilter(VecOrigin, VecAngles, MASK_OPAQUE, RayType_Infinite, TraceRayDontHitSelf, param1); + if(TR_DidHit(null)) + { + TR_GetEndPosition(VecOrigin); + } + else + { + PrintToChat(param1, "[SM] Vector out of world geometry. Spawning on current position instead"); + } + VecAngles[0] = 0.0; + VecAngles[2] = 0.0; + g_vecLastEntityAngles[param1] = VecAngles; + g_iLastObject[param1] = prop; + DispatchKeyValueVector(prop, "angles", VecAngles); + DispatchSpawn(prop); + TeleportEntity(prop, VecOrigin, NULL_VECTOR, NULL_VECTOR); + g_bSpawned[prop] = true; + g_vecEntityAngles[prop] = VecAngles; + char name[256]; + GetClientName(param1, name, sizeof(name)); + LogSpawn("%s spawned a static object with model <%s>", name, model); + } + else if(g_iCategory[param1] == 6) + { + float VecOrigin[3]; + float VecAngles[3]; + int prop = CreateEntityByName("prop_dynamic_override"); + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + SetEntProp(prop, Prop_Send, "m_nSolidType", 6); + DispatchSpawn(prop); + GetClientAbsOrigin(param1, VecOrigin); + GetClientEyeAngles(param1, VecAngles); + VecAngles[0] = 0.0; + VecAngles[2] = 0.0; + g_vecLastEntityAngles[param1] = VecAngles; + g_iLastObject[param1] = prop; + DispatchKeyValueVector(prop, "angles", VecAngles); + DispatchSpawn(prop); + TeleportEntity(prop, VecOrigin, NULL_VECTOR, NULL_VECTOR); + g_bSpawned[prop] = true; + g_vecEntityAngles[prop] = VecAngles; + char name[256]; + GetClientName(param1, name, sizeof(name)); + LogSpawn("%s spawned a static object with model <%s>", name, model); + } + switch(g_iSubCategory[param1]) + { + case 1: + { + g_iVehiclesMenuPosition[param1] = menu.Selection; + DisplayVehiclesMenu(param1); + } + case 2: + { + g_iFoliageMenuPosition[param1] = menu.Selection; + DisplayFoliageMenu(param1); + } + case 3: + { + g_iFurnitureMenuPosition[param1] = menu.Selection; + DisplayFurnitureMenu(param1); + } + case 4: + { + g_iFurnishingsMenuPosition[param1] = menu.Selection; + DisplayFurnishingsMenu(param1); + } + case 5: + { + g_iAppliancesMenuPosition[param1] = menu.Selection; + DisplayAppliancesMenu(param1); + + } + case 6: + { + g_iBuildingsMenuPosition[param1] = menu.Selection; + DisplayBuildingsMenu(param1); + } + case 7: + { + g_iScaffoldingMenuPosition[param1] = menu.Selection; + DisplayScaffoldingMenu(param1); + } + case 8: + { + g_iDoorsMenuPosition[param1] = menu.Selection; + DisplayDoorsMenu(param1); + } + case 9: + { + g_iWindowsMenuPosition[param1] = menu.Selection; + DisplayWindowsMenu(param1); + } + case 10: + { + g_iLightsMenuPosition[param1] = menu.Selection; + DisplayLightsMenu(param1); + } + case 11: + { + g_iSignssMenuPosition[param1] = menu.Selection; + DisplaySignsMenu(param1); + + } + case 12: + { + g_iFencingMenuPosition[param1] = menu.Selection; + DisplayFencingMenu(param1); + } + case 13: + { + g_iRailingMenuPosition[param1] = menu.Selection; + DisplayRailingMenu(param1); + } + case 14: + { + g_iStairsMenuPosition[param1] = menu.Selection; + DisplayStairsMenu(param1); + } + case 15: + { + g_iOfficeMenuPosition[param1] = menu.Selection; + DisplayOfficeMenu(param1); + } + case 16: + { + g_iStreetsMenuPosition[param1] = menu.Selection; + DisplayStreetsMenu(param1); + } + case 17: + { + g_iFairgroundsMenuPosition[param1] = menu.Selection; + DisplayFairgroundsMenu(param1); + } + case 18: + { + g_iMallMenuPosition[param1] = menu.Selection; + DisplayMallMenu(param1); + } + case 19: + { + g_iConstructionMenuPosition[param1] = menu.Selection; + DisplayConstructionMenu(param1); + } + case 20: + { + g_iGeneralMiscMenuPosition[param1] = menu.Selection; + DisplayGeneralMiscMenu(param1); + } + case 21: + { + g_iExteriorMiscMenuPosition[param1] = menu.Selection; + DisplayExteriorMiscMenu(param1); + } + case 22: + { + g_iInteriorMiscMenuPosition[param1] = menu.Selection; + DisplayInteriorMiscMenu(param1); + } + case 23: + { + g_iDebrisMenuPosition[param1] = menu.Selection; + DisplayDebrisMenu(param1); + } + case 24: + { + g_iJunkMenuPosition[param1] = menu.Selection; + DisplayJunkMenu(param1); + } + case 25: + { + g_iPipesMenuPosition[param1] = menu.Selection; + DisplayPipesMenu(param1); + } + case 26: + { + g_iBodiesGenericMenuPosition[param1] = menu.Selection; + DisplayBodiesGenericMenu(param1); + } + case 27: + { + g_iBodiesSwampMenuPosition[param1] = menu.Selection; + DisplayBodiesSwampMenu(param1); + } + case 28: + { + g_iBodiesSugarMillMenuPosition[param1] = menu.Selection; + DisplayBodiesSugarMill(param1); + } + case 29: + { + g_iBodiesCemetaryMenuPosition[param1] = menu.Selection; + DisplayBodiesCemetaryMenu(param1); + } + case 30: + { + g_iInfectedMenuPosition[param1] = menu.Selection; + DisplayInfectedMenu(param1); + } + case 31: + { + g_iSkyboxMenuPosition[param1] = menu.Selection; + DisplaySkyboxMenu(param1); + } + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack) + { + switch(g_iCategory[param1]) + { + case 1: + { + BuildPhysicsCursorMenu(param1); + } + case 2: + { + BuildPhysicsPositionMenu(param1); + } + case 3: + { + BuildDynamicCursorMenu(param1); + } + case 4: + { + BuildDynamicPositionMenu(param1); + } + case 5: + { + BuildStaticCursorMenu(param1); + } + case 6: + { + BuildStaticPositionMenu(param1); + } + case 7: + { + BuildStaticPositionMenu(param1); + } + case 8: + { + BuildStaticPositionMenu(param1); + } + case 9: + { + BuildStaticPositionMenu(param1); + } + } + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public int MenuHandler_PropPosition(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + switch(g_iMoveCategory[param1]) + { + case 1: + { + if(g_iLastObject[param1] <= 0 || !IsValidEntity(g_iLastObject[param1])) + { + PrintToChat(param1, "[SM] The last object is not valid anymore or you haven't spawned anything yet"); + DisplayRotateMenu(param1); + return; + } + int Object = g_iLastObject[param1]; + + float vecAngles[3]; + vecAngles[0] = g_vecLastEntityAngles[param1][0]; + vecAngles[1] = g_vecLastEntityAngles[param1][1]; + vecAngles[2] = g_vecLastEntityAngles[param1][2]; + + if(strcmp(menucmd, "rotate1x")== 0) + { + vecAngles[0] += 1; + } + if(strcmp(menucmd, "rotate-1x")== 0) + { + vecAngles[0] -= 1; + } + else if(strcmp(menucmd, "rotate10x")== 0) + { + vecAngles[0] += 10; + } + else if(strcmp(menucmd, "rotate-10x")== 0) + { + vecAngles[0] -= 10; + } + else if(strcmp(menucmd, "rotate15x")== 0) + { + vecAngles[0] += 15; + } + else if(strcmp(menucmd, "rotate-15x")== 0) + { + vecAngles[0] -= 15; + } + else if(strcmp(menucmd, "rotate45x")== 0) + { + vecAngles[0] += 45; + } + else if(strcmp(menucmd, "rotate90x")== 0) + { + vecAngles[0] += 90; + } + else if(strcmp(menucmd, "rotate180x")== 0) + { + vecAngles[0] += 180; + } + else if(strcmp(menucmd, "rotate1y")== 0) + { + vecAngles[1] += 1; + } + else if(strcmp(menucmd, "rotate-1y")== 0) + { + vecAngles[1] -= 1; + } + else if(strcmp(menucmd, "rotate10y")== 0) + { + vecAngles[1] += 10; + } + else if(strcmp(menucmd, "rotate-10y")== 0) + { + vecAngles[1] -= 10; + } + else if(strcmp(menucmd, "rotate15y")== 0) + { + vecAngles[1] += 15; + } + else if(strcmp(menucmd, "rotate-15y")== 0) + { + vecAngles[1] -= 15; + } + else if(strcmp(menucmd, "rotate45y")== 0) + { + vecAngles[1] += 45; + } + else if(strcmp(menucmd, "rotate90y")== 0) + { + vecAngles[1] += 90; + } + else if(strcmp(menucmd, "rotate180y")== 0) + { + vecAngles[1] += 180; + } + else if(strcmp(menucmd, "rotate1z")== 0) + { + vecAngles[2] += 1; + } + else if(strcmp(menucmd, "rotate-1z")== 0) + { + vecAngles[2] -= 1; + } + else if(strcmp(menucmd, "rotate10z")== 0) + { + vecAngles[2] += 10; + } + else if(strcmp(menucmd, "rotate-10z")== 0) + { + vecAngles[2] -= 10; + } + else if(strcmp(menucmd, "rotate15z")== 0) + { + vecAngles[2] += 15; + } + else if(strcmp(menucmd, "rotate-15z")== 0) + { + vecAngles[2] -= 15; + } + else if(strcmp(menucmd, "rotate45z")== 0) + { + vecAngles[2] += 45; + } + else if(strcmp(menucmd, "rotate90z")== 0) + { + vecAngles[2] += 90; + } + else if(strcmp(menucmd, "rotate180z")== 0) + { + vecAngles[2] += 180; + } + + g_vecLastEntityAngles[param1] = vecAngles; + TeleportEntity(Object, NULL_VECTOR, vecAngles, NULL_VECTOR); + g_vecEntityAngles[g_iLastObject[param1]] = vecAngles; + + g_iRotateMenuPosition[param1] = menu.Selection; + DisplayRotateMenu(param1); + } + case 2: + { + if(g_iLastObject[param1] <= 0 || !IsValidEntity(g_iLastObject[param1])) + { + PrintToChat(param1, "[SM] The last object is not valid anymore or you haven't spawned anything yet"); + DisplayMoveMenu(param1); + return; + } + + int Object = g_iLastObject[param1]; + float vecOrigin[3]; + GetEntPropVector(Object, Prop_Data, "m_vecOrigin", vecOrigin); + + if(strcmp(menucmd, "moveup1")== 0) + { + vecOrigin[2]+= 1; + } + if(strcmp(menucmd, "moveup10")== 0) + { + vecOrigin[2]+= 10; + } + if(strcmp(menucmd, "moveup30")== 0) + { + vecOrigin[2]+= 30; + } + else if(strcmp(menucmd, "movedown1")== 0) + { + vecOrigin[2]-= 1; + } + else if(strcmp(menucmd, "movedown10")== 0) + { + vecOrigin[2]-= 10; + } + else if(strcmp(menucmd, "movedown30")== 0) + { + vecOrigin[2]-= 30; + } + else if(strcmp(menucmd, "moveright1")== 0) + { + vecOrigin[1]+= 1; + } + else if(strcmp(menucmd, "moveright10")== 0) + { + vecOrigin[1]+= 10; + } + else if(strcmp(menucmd, "moveright30")== 0) + { + vecOrigin[1]+= 30; + } + else if(strcmp(menucmd, "moveleft1")== 0) + { + vecOrigin[1]-= 1; + } + else if(strcmp(menucmd, "moveleft10")== 0) + { + vecOrigin[1]-= 10; + } + else if(strcmp(menucmd, "moveleft30")== 0) + { + vecOrigin[1]-= 30; + } + else if(strcmp(menucmd, "moveforward1")== 0) + { + vecOrigin[0]+= 1; + } + else if(strcmp(menucmd, "moveforward10")== 0) + { + vecOrigin[0]+= 10; + } + else if(strcmp(menucmd, "moveforward30")== 0) + { + vecOrigin[0]+= 30; + } + else if(strcmp(menucmd, "movebackward1")== 0) + { + vecOrigin[0]-= 1; + } + else if(strcmp(menucmd, "movebackward10")== 0) + { + vecOrigin[0]-= 10; + } + else if(strcmp(menucmd, "movebackward30")== 0) + { + vecOrigin[0]-= 30; + } + TeleportEntity(Object, vecOrigin, NULL_VECTOR, NULL_VECTOR); + + g_iMoveMenuPosition[param1] = menu.Selection; + DisplayMoveMenu(param1); + } + } + } + case MenuAction_Cancel: + { + if(param2 == MenuCancel_ExitBack) + { + BuildEditPropMenu(param1); + } + } + case MenuAction_End: + { + delete menu; + } + } +} + +public bool TraceRayDontHitSelf(int entity, int mask, any data) +{ + if(entity == data) // Check if the TraceRay hit the itself. + { + return false; // Don't let the entity be hit + } + return true; // It didn't hit itself +} + +void DeleteLookingEntity(int client) +{ + float VecOrigin[3]; + float VecAngles[3]; + GetClientEyePosition(client, VecOrigin); + GetClientEyeAngles(client, VecAngles); + TR_TraceRayFilter(VecOrigin, VecAngles, MASK_PLAYERSOLID, RayType_Infinite, TraceRayDontHitSelf, client); + if(TR_DidHit(null)) + { + int Object = TR_GetEntityIndex(null); + if(Object > 0 && IsValidEntity(Object) && IsValidEdict(Object)) + { + char class[256]; + GetEdictClassname(Object, class, sizeof(class)); + if(strcmp(class, "prop_physics") == 0 + || strcmp(class, "prop_dynamic") == 0 + || strcmp(class, "prop_physics_override") == 0 + || strcmp(class, "prop_dynamic_override") == 0) + { + g_bSpawned[Object] = false; + g_bUnsolid[Object] = false; + g_vecEntityAngles[Object][0] = 0.0; + g_vecEntityAngles[Object][1] = 0.0; + g_vecEntityAngles[Object][2] = 0.0; + + char m_ModelName[PLATFORM_MAX_PATH]; + GetEntPropString(Object, Prop_Data, "m_ModelName", m_ModelName, sizeof(m_ModelName)); + PrintToChat(client, "[SM] %T", "Object Model", client, Object, m_ModelName); + + float position[3]; + GetEntPropVector(Object, Prop_Send, "m_vecOrigin", position); + PrintToChat(client, "[SM] %T", "Object Position", client, Object, position[0], position[1], position[2]); + + float angle[3]; + GetEntPropVector(Object, Prop_Data, "m_angRotation", angle); + PrintToChat(client, "[SM] %T", "Object Angle", client, Object, angle[0], angle[1], angle[2]); + + AcceptEntityInput(Object, "KillHierarchy"); + PrintToChat(client, "[SM] %T", "Successfully removed an object", client, Object); + if(Object == g_iLastObject[client]) + { + g_iLastObject[client] = -1; + g_vecLastEntityAngles[client][0] = 0.0; + g_vecLastEntityAngles[client][1] = 0.0; + g_vecLastEntityAngles[client][2] = 0.0; + g_bGrab[client] = false; + g_bGrabbed[Object] = false; + } + if(Object == g_iLastGrabbedObject[client]) + { + g_iLastGrabbedObject[client] = -1; + } + return; + } + } + } + else + { + int Object = GetClientAimTarget(client, false); + if(Object == -2) + { + PrintToChat(client, "[SM] %T","This plugin won't work in this game",client); + SetFailState("Unhandled Behaviour"); + } + if(Object > 0 && IsValidEntity(Object)) + { + char class[256]; + GetEdictClassname(Object, class, sizeof(class)); + if(strcmp(class, "prop_physics") == 0 + || strcmp(class, "prop_dynamic") == 0 + || strcmp(class, "prop_physics_override") == 0 + || strcmp(class, "prop_dynamic_override") == 0) + { + g_bSpawned[Object] = false; + g_bUnsolid[Object] = false; + g_vecEntityAngles[Object][0] = 0.0; + g_vecEntityAngles[Object][1] = 0.0; + g_vecEntityAngles[Object][2] = 0.0; + AcceptEntityInput(Object, "KillHierarchy"); + PrintToChat(client, "[SM] %T", "Successfully removed an object", client, Object); + if(Object == g_iLastObject[client]) + { + g_iLastObject[client] = -1; + g_vecLastEntityAngles[client][0] = 0.0; + g_vecLastEntityAngles[client][1] = 0.0; + g_vecLastEntityAngles[client][2] = 0.0; + if(Object == g_iLastGrabbedObject[client]) + { + g_iLastGrabbedObject[client] = -1; + } + } + return; + } + } + } + PrintToChat(client, "[SM] %T","You are not looking to a valid object",client); +} + +void DeleteAllProps() +{ + CheatCommand(_, "ent_fire", "l4d2_spawn_props_prop KillHierarchy"); + for(int i=1; i<=MaxClients; i++) + { + g_iLastObject[i] = -1; + g_vecLastEntityAngles[i][0] = 0.0; + g_vecLastEntityAngles[i][1] = 0.0; + g_vecLastEntityAngles[i][2] = 0.0; + g_bGrab[i] = false; + g_iLastGrabbedObject[i] = -1; + } + for(int i=MaxClients; i < ARRAY_SIZE; i++) + { + if(g_bSpawned[i]) + { + g_bGrabbed[i] = false; + g_bSpawned[i] = false; + g_bUnsolid[i] = false; + g_vecEntityAngles[i][0] = 0.0; + g_vecEntityAngles[i][1] = 0.0; + g_vecEntityAngles[i][2] = 0.0; + if(IsValidEntity(i)) + { + AcceptEntityInput(i, "Kill"); + } + } + } +} + +void CheatCommand(int client = 0, char[] command, char[] arguments="") +{ + if (!client || !IsClientInGame(client)) + { + for (int target = 1; target <= MaxClients; target++) + { + if (IsClientInGame(target)) + { + client = target; + break; + } + } + + if (!client || !IsClientInGame(client)) return; + } + + int userflags = GetUserFlagBits(client); + SetUserFlagBits(client, ADMFLAG_ROOT); + int flags = GetCommandFlags(command); + SetCommandFlags(command, flags & ~FCVAR_CHEAT); + FakeClientCommand(client, "%s %s", command, arguments); + SetCommandFlags(command, flags); + SetUserFlagBits(client, userflags); +} + +//Disabled right now +void DeleteLastProp(int client) +{ + int Object = g_iLastObject[client]; + if(Object > 0 && IsValidEntity(Object)) + { + char class[256]; + GetEdictClassname(Object, class, sizeof(class)); + if(strcmp(class, "prop_physics") == 0 + || strcmp(class, "prop_dynamic") == 0 + || strcmp(class, "prop_physics_override") == 0 + || strcmp(class, "prop_dynamic_override") == 0) + { + AcceptEntityInput(g_iLastObject[client], "KillHierarchy"); + PrintToChat(client, "[SM] %T","Succesfully deleted the last spawned object",client); + g_iLastObject[client] = -1; + g_vecLastEntityAngles[client][0] = 0.0; + g_vecLastEntityAngles[client][1] = 0.0; + g_vecLastEntityAngles[client][2] = 0.0; + g_bSpawned[Object] = false; + g_bUnsolid[Object] = false; + g_vecEntityAngles[Object][0] = 0.0; + g_vecEntityAngles[Object][1] = 0.0; + g_vecEntityAngles[Object][2] = 0.0; + g_bGrab[client] = false; + g_bGrabbed[Object] = false; + if(Object == g_iLastGrabbedObject[client]) + { + g_iLastGrabbedObject[client] = -1; + } + return; + } + else + { + PrintToChat(client, "[SM] %T", "The last spawned object index is not an object anymore!", client, Object); + g_iLastObject[client] = -1; + g_vecLastEntityAngles[client][0] = 0.0; + g_vecLastEntityAngles[client][1] = 0.0; + g_vecLastEntityAngles[client][2] = 0.0; + g_bSpawned[Object] = false; + g_bUnsolid[Object] = false; + g_vecEntityAngles[Object][0] = 0.0; + g_vecEntityAngles[Object][1] = 0.0; + g_vecEntityAngles[Object][2] = 0.0; + } + } + else if(Object > 0 && !IsValidEntity(Object)) + { + PrintToChat(client, "[SM] %T","The last object is not valid anymore",client); + } + else if(Object <= 0) + { + PrintToChat(client, "[SM] %T","You haven't spawned anything yet",client); + } +} + +void LogSpawn(const char[] format, any ...) +{ + if(!g_cvarLog.BoolValue) + { + return; + } + char buffer[512]; + VFormat(buffer, sizeof(buffer), format, 2); + File file; + char FileName[256]; + char sTime[256]; + FormatTime(sTime, sizeof(sTime), "%Y%m%d"); + BuildPath(Path_SM, FileName, sizeof(FileName), "logs/objects_%s.log", sTime); + file = OpenFile(FileName, "a+"); + FormatTime(sTime, sizeof(sTime), "%b %d |%H:%M:%S| %Y"); + file.WriteLine("%s: %s", sTime, buffer); + FlushFile(file); + CloseHandle(file); +} + +public Action CmdSaveMap(int client, int args) +{ + SaveMapStripper(client); + return Plugin_Handled; +} + +void SaveMapStripper(int client) +{ + #if DEBUG + LogSpawn("[DEBUG] was called by %N", client); + #endif + LogSpawn("%N saved the objects for this map on a 'Stripper' file format", client); + PrintToChat(client, "\x04[SM] Saving the content. Please Wait"); + char FileName[256]; + char map[256]; + char classname[256]; + File file; + GetCurrentMap(map, sizeof(map)); + BuildPath(Path_SM, FileName, sizeof(FileName), "../stripper/maps/%s.cfg", map); + + if(FileExists(FileName)) + { + PrintHintText(client, "%T", "The file already exists.", client); + } + #if DEBUG + LogSpawn("[DEBUG] File stated, proceed"); + #endif + file = OpenFile(FileName, "a+"); + #if DEBUG + LogSpawn("[DEBUG] File Opened, proceed"); + #endif + if(file == null) + { + #if DEBUG + LogSpawn("[DEBUG] File Invalid, proceed"); + #endif + PrintToChat(client, "[SM] Failed to create or overwrite the map file"); + PrintToChat(client, "\x04[SM] Something was probably missing during installation"); + PrintHintText(client, "[SM] Probably missing addons/stripper folder"); + PrintToConsole(client, "[SM] Unable to open, write, or find the file!"); + PrintCenterText(client, "[SM] FAILURE"); + return; + } + + float vecOrigin[3]; + float vecAngles[3]; + char sModel[256]; + char sTime[256]; + int iOrigin[3], iAngles[3]; + FormatTime(sTime, sizeof(sTime), "%Y/%m/%d"); + file.WriteLine(";----------FILE MODIFICATION (YY/MM/DD): [%s] ---------------||", sTime); + file.WriteLine(";----------BY: %N----------------------||", client); + file.WriteLine(""); + file.WriteLine("add:"); + #if DEBUG + LogSpawn("[DEBUG] Wrote first information line"); + #endif + for(int i=MaxClients; i < ARRAY_SIZE; i++) + { + #if DEBUG + LogSpawn("[DEBUG] CHECK: %i", i); + #endif + if(g_bSpawned[i] && IsValidEntity(i)) + { + GetEdictClassname(i, classname, sizeof(classname)); + #if DEBUG + LogSpawn("[DEBUG] Possible Entity Found: %i <%s>", i, classname); + #endif + if(StrContains(classname, "prop_dynamic") >= 0 || StrContains(classname, "prop_physics") >= 0) + { + GetEntPropVector(i, Prop_Send, "m_vecOrigin", vecOrigin); + vecAngles = g_vecEntityAngles[i]; + GetEntPropString(i, Prop_Data, "m_ModelName", sModel, sizeof(sModel)); + iOrigin[0] = RoundToFloor(vecOrigin[0]); + iOrigin[1] = RoundToFloor(vecOrigin[1]); + iOrigin[2] = RoundToFloor(vecOrigin[2]); + + iAngles[0] = RoundToFloor(vecAngles[0]); + iAngles[1] = RoundToFloor(vecAngles[1]); + iAngles[2] = RoundToFloor(vecAngles[2]); + file.WriteLine("{"); + if(StrContains(classname, "physics") < 0) + { + if(g_bUnsolid[i]) + { + file.WriteLine(" \"solid\" \"0\""); + } + else + { + file.WriteLine(" \"solid\" \"6\""); + } + } + file.WriteLine(" \"origin\" \"%i %i %i\"", iOrigin[0], iOrigin[1], iOrigin[2]); + file.WriteLine(" \"angles\" \"%i %i %i\"", iAngles[0], iAngles[1], iAngles[2]); + file.WriteLine(" \"model\" \"%s\"", sModel); + file.WriteLine(" \"classname\" \"%s\"", classname); + file.WriteLine("}"); + file.WriteLine(""); + #if DEBUG + LogSpawn("[DEBUG] END: %i", i); + #endif + } + } + } + #if DEBUG + LogSpawn("[DEBUG] Wrote all entities"); + #endif + FlushFile(file); + CloseHandle(file); + PrintToChat(client, "\x03[SM] %T (%s)", "Succesfully saved the map data", client, FileName); + #if DEBUG + LogSpawn("[DEBUG] END"); + #endif +} + +void SaveRoutingPath(int client, int type) +{ + #if DEBUG + LogSpawn("[DEBUG] was called by %N", client); + #endif + LogSpawn("%N saved the objects for this map on a \"Routing\" file format", client); + PrintToChat(client, "\x04[SM] Saving the content. Please Wait"); + char FileName[256]; + char map[256]; + char classname[256]; + char targetname[256]; + File file; + bool Exists = false; + GetCurrentMap(map, sizeof(map)); + BuildPath(Path_SM, FileName, sizeof(FileName), "../stripper/routing/%s.cfg", map); + if(FileExists(FileName)) + { + PrintHintText(client, "%T", "The file already exists.", client); + Exists = true; + } + file = OpenFile(FileName, "a+"); + if(file == null) + { + PrintToChat(client, "[SM] Failed to create or overwrite the map file"); + PrintToChat(client, "\x04[SM] Something was probably missing during installation"); + PrintHintText(client, "[SM] Probably missing addons/stripper/maps/routing folder"); + PrintToConsole(client, "[SM] Unable to open, write, or find the file!"); + PrintCenterText(client, "[SM] FAILURE"); + return; + } + float vecOrigin[3]; + float vecAngles[3]; + char sModel[256]; + char sTime[256]; + int iOrigin[3], iAngles[3]; + FormatTime(sTime, sizeof(sTime), "%Y/%m/%d"); + file.WriteLine(";----------FILE MODIFICATION (YY/MM/DD): [%s] ---------------||", sTime); + file.WriteLine(";----------BY: %N----------------------||", client); + file.WriteLine(""); + switch(type) + { + case RouteType_Easy: + { + file.WriteLine(";This part was generated for an \"Easy\" routing path."); + Format(targetname, sizeof(targetname), "easy_route_blocker"); + } + case RouteType_Medium: + { + file.WriteLine(";This part was generated for a \"Medium\" routing path."); + Format(targetname, sizeof(targetname), "medium_route_blocker"); + } + case RouteType_Hard: + { + file.WriteLine(";This part was generated for a \"Hard\" routing path."); + Format(targetname, sizeof(targetname), "hard_route_blocker"); + } + } + file.WriteLine(""); + file.WriteLine("add:"); + + if(!Exists) + { + //First, wee add the necessary relays + + file.WriteLine("; plugin trigger relay"); + file.WriteLine("; will get fired by Plugin ONLY IN VERSUS, so it doesnt break coop"); + file.WriteLine("{"); + file.WriteLine(" \"origin\" \"0 0 0\""); + file.WriteLine(" \"spawnflags\" \"1\""); + file.WriteLine(" \"targetname\" \"relay_routing_init\""); + file.WriteLine(" \"classname\" \"logic_relay\""); + file.WriteLine(" "); + file.WriteLine(" ; destroy Valve routing entities so they dont interfere"); + file.WriteLine(" "); + file.WriteLine(" \"OnTrigger\" \"director_queryKill0-1\""); + file.WriteLine("}"); + file.WriteLine(""); + file.WriteLine("{"); + file.WriteLine(" \"origin\" \"0 0 0\""); + file.WriteLine(" \"spawnflags\" \"1\""); + file.WriteLine(" \"targetname\" \"relay_routing_disabledbydefault\""); + file.WriteLine(" \"classname\" \"logic_auto\""); + file.WriteLine(" "); + file.WriteLine(" \"OnMapSpawn\" \"easy_route_blockerDisable0-1\""); + file.WriteLine(" \"OnMapSpawn\" \"easy_route_blockerDisableCollision0-1\""); + file.WriteLine(" \"OnMapSpawn\" \"medium_route_blockerDisable0-1\""); + file.WriteLine(" \"OnMapSpawn\" \"medium_route_blockerDisableCollision0-1\""); + file.WriteLine(" \"OnMapSpawn\" \"hard_route_blockerDisable0-1\""); + file.WriteLine(" \"OnMapSpawn\" \"hard_route_blockerDisableCollision0-1\""); + file.WriteLine("}"); + file.WriteLine("; config existence checking entity"); + file.WriteLine("{"); + file.WriteLine(" \"origin\" \"0 0 0\""); + file.WriteLine(" \"targetname\" \"map_has_routing\""); + file.WriteLine(" \"noise\" \"0\""); + file.WriteLine(" \"minAngerRange\" \"1\""); + file.WriteLine(" \"maxAngerRange\" \"10\""); + file.WriteLine(" \"classname\" \"logic_director_query\""); + file.WriteLine(" \"OutAnger\" \"DoHeadBangInValue0-1\""); + file.WriteLine("}"); + file.WriteLine(""); + file.WriteLine("; easy path"); + file.WriteLine("{"); + file.WriteLine(" \"origin\" \"0 0 0\""); + file.WriteLine(" \"targetname\" \"relay_easy_route_spawn\""); + file.WriteLine(" \"spawnflags\" \"0\""); + file.WriteLine(" \"classname\" \"logic_relay\""); + file.WriteLine(" \"OnTrigger\" \"easy_route_blockerEnable0-1\""); + file.WriteLine(" \"OnTrigger\" \"easy_route_blockerEnableCollision0-1\""); + file.WriteLine("}"); + file.WriteLine(""); + file.WriteLine("; medium path"); + file.WriteLine("{"); + file.WriteLine(" \"origin\" \"0 0 0\""); + file.WriteLine(" \"targetname\" \"relay_medium_route_spawn\""); + file.WriteLine(" \"spawnflags\" \"0\""); + file.WriteLine(" \"classname\" \"logic_relay\""); + file.WriteLine(" \"OnTrigger\" \"medium_route_blockerEnable0-1\""); + file.WriteLine(" \"OnTrigger\" \"medium_route_blockerEnableCollision0-1\""); + file.WriteLine("}"); + file.WriteLine(""); + file.WriteLine("; hard path"); + file.WriteLine("{"); + file.WriteLine(" \"origin\" \"0 0 0\""); + file.WriteLine(" \"targetname\" \"relay_hard_route_spawn\""); + file.WriteLine(" \"spawnflags\" \"0\""); + file.WriteLine(" \"classname\" \"logic_relay\""); + file.WriteLine(" \"OnTrigger\" \"hard_route_blockerEnable0-1\""); + file.WriteLine(" \"OnTrigger\" \"hard_route_blockerEnableCollision0-1\""); + file.WriteLine("}"); + file.WriteLine(""); + } + for(int i=MaxClients; i < ARRAY_SIZE; i++) + { + if(g_bSpawned[i] && IsValidEntity(i)) + { + GetEdictClassname(i, classname, sizeof(classname)); + if(StrContains(classname, "prop_dynamic") >= 0 || StrContains(classname, "prop_physics") >= 0) + { + GetEntPropVector(i, Prop_Send, "m_vecOrigin", vecOrigin); + vecAngles = g_vecEntityAngles[i]; + GetEntPropString(i, Prop_Data, "m_ModelName", sModel, sizeof(sModel)); + iOrigin[0] = RoundToFloor(vecOrigin[0]); + iOrigin[1] = RoundToFloor(vecOrigin[1]); + iOrigin[2] = RoundToFloor(vecOrigin[2]); + + iAngles[0] = RoundToFloor(vecAngles[0]); + iAngles[1] = RoundToFloor(vecAngles[1]); + iAngles[2] = RoundToFloor(vecAngles[2]); + file.WriteLine("{"); + if(StrContains(classname, "physics") < 0) + { + if(g_bUnsolid[i]) + { + file.WriteLine(" \"solid\" \"0\""); + } + else + { + file.WriteLine(" \"solid\" \"6\""); + } + } + file.WriteLine(" \"origin\" \"%i %i %i\"", iOrigin[0], iOrigin[1], iOrigin[2]); + file.WriteLine(" \"angles\" \"%i %i %i\"", iAngles[0], iAngles[1], iAngles[2]); + file.WriteLine(" \"model\" \"%s\"", sModel); + file.WriteLine(" \"targetname\" \"%s\"", targetname); + file.WriteLine(" \"classname\" \"%s\"", classname); + file.WriteLine("}"); + file.WriteLine(""); + } + } + } + FlushFile(file); + CloseHandle(file); + PrintToChat(client, "\x03[SM] %T (%s)", "Succesfully saved the map data", client, FileName); +} + +void SavePluginProps(int client) +{ + LogSpawn("%N saved the objects for this map on a \"Plugin Cache\" file format", client); + PrintToChat(client, "\x04[SM] Saving the content. Please Wait"); + char FileName[256]; + char map[256]; + char classname[256]; + char FileNameS[256]; + char FileNameT[256]; + File file; + GetCurrentMap(map, sizeof(map)); + BuildPath(Path_SM, FileNameS, sizeof(FileNameS), "../stripper/plugin_cache/%s", map); + Format(FileName, sizeof(FileName), "%s_1.txt", FileNameS); + int map_number = 0; + if(FileExists(FileName)) + { + map_number = GetNextMapNumber(FileNameS); + if(map_number <= 0) + { + PrintToChat(client, "\x04[SM] Fatal Error: Too Many path files for this map! (Max: %i)", MAX_PATHS); + return; + } + Format(FileNameT, sizeof(FileNameT), "%s_%i.txt", FileNameS, map_number); + } + else + { + Format(FileNameT, sizeof(FileNameT), "%s_1.txt", FileNameS); + } + file = OpenFile(FileNameT, "a+"); + if(file == null) + { + PrintToChat(client, "[SM] Failed to create or overwrite the map file"); + PrintToChat(client, "\x04[SM] Something was probably missing during installation"); + PrintHintText(client, "[SM] Probably missing addons/stripper/maps/plugin_cache folder"); + PrintToConsole(client, "[SM] Unable to open, write, or find the file!"); + PrintCenterText(client, "[SM] FAILURE"); + return; + } + CreateInitFile(); + float vecOrigin[3]; + float vecAngles[3]; + char sModel[256]; + char sTime[256]; + int iOrigin[3], iAngles[3]; + int count = 0; + FormatTime(sTime, sizeof(sTime), "%Y/%m/%d"); + file.WriteLine("//----------FILE MODIFICATION (YY/MM/DD): [%s] ---------------||", sTime); + file.WriteLine("//----------BY: %N----------------------||", client); + file.WriteLine(""); + file.WriteLine("\"Objects_Cache\""); + file.WriteLine("{"); + for(int i=MaxClients; i < ARRAY_SIZE; i++) + { + if(g_bSpawned[i] && IsValidEntity(i)) + { + GetEdictClassname(i, classname, sizeof(classname)); + if(StrContains(classname, "prop_dynamic") >= 0 || StrContains(classname, "prop_physics") >= 0) + { + GetEntPropVector(i, Prop_Send, "m_vecOrigin", vecOrigin); + vecAngles = g_vecEntityAngles[i]; + GetEntPropString(i, Prop_Data, "m_ModelName", sModel, sizeof(sModel)); + iOrigin[0] = RoundToFloor(vecOrigin[0]); + iOrigin[1] = RoundToFloor(vecOrigin[1]); + iOrigin[2] = RoundToFloor(vecOrigin[2]); + + iAngles[0] = RoundToFloor(vecAngles[0]); + iAngles[1] = RoundToFloor(vecAngles[1]); + iAngles[2] = RoundToFloor(vecAngles[2]); + count++; + + file.WriteLine(" \"object_%i\"", count); + file.WriteLine(" {"); + if(StrContains(classname, "physics") < 0) + { + if(g_bUnsolid[i]) + { + file.WriteLine(" \"solid\" \"0\""); + } + else + { + file.WriteLine(" \"solid\" \"6\""); + } + } + file.WriteLine(" \"origin\" \"%i %i %i\"", iOrigin[0], iOrigin[1], iOrigin[2]); + file.WriteLine(" \"angles\" \"%i %i %i\"", iAngles[0], iAngles[1], iAngles[2]); + file.WriteLine(" \"model\" \"%s\"", sModel); + file.WriteLine(" \"classname\" \"%s\"", classname); + file.WriteLine(" }"); + file.WriteLine(" "); + } + } + } + file.WriteLine(" \"total_cache\""); + file.WriteLine(" {"); + file.WriteLine(" \"total\" \"%i\"", count); + file.WriteLine(" }"); + file.WriteLine("}"); + + FlushFile(file); + CloseHandle(file); + PrintToChat(client, "\x03[SM] %T (%s)", "Succesfully saved the map data", client, FileNameT); +} + +public Action CmdLoad(int client, int args) +{ + if(args < 1) + { + PrintToChat(client, "[SM] Specify a map number"); + } + char arg[5]; + GetCmdArgString(arg, sizeof(arg)); + int number = StringToInt(arg); + LoadPluginProps(client, number); + return Plugin_Handled; +} + +void LoadPluginProps(int client, int number) +{ + LogSpawn("%N loaded the objects for this map", client); + PrintToChat(client, "\x04[SM] Loading content. Please Wait"); + char KvFileName[256]; + char map[256]; + char name[256]; + GetCurrentMap(map, sizeof(map)); + BuildPath(Path_SM, KvFileName, sizeof(KvFileName), "../stripper/plugin_cache/%s_%i.txt", map, number); + if(!FileExists(KvFileName)) + { + PrintToChat(client, "\x04[SM] The file does not exist"); + PrintHintText(client, "\x04[SM] The file does not exist"); + return; + } + KeyValues keyvalues = new KeyValues("Objects_Cache"); + keyvalues.ImportFromFile(KvFileName); + keyvalues.Rewind(); + if(keyvalues.JumpToKey("total_cache")) + { + int max = keyvalues.GetNum("total", 0); + if(max <= 0) + { + PrintToChat(client, "\x04[SM] No objects found in the cache"); + return; + } + char model[256]; + char class[64]; + float vecOrigin[3]; + float vecAngles[3]; + int solid; + keyvalues.Rewind(); + for(int count=1; count <= max; count++) + { + Format(name, sizeof(name), "object_%i", count); + if(keyvalues.JumpToKey(name)) + { + solid = keyvalues.GetNum("solid"); + keyvalues.GetVector("origin", vecOrigin); + keyvalues.GetVector("angles", vecAngles); + keyvalues.GetString("model", model, sizeof(model)); + keyvalues.GetString("classname", class, sizeof(class)); + int prop = -1; + keyvalues.Rewind(); + if(StrContains(class, "prop_physics") >= 0) + { + prop = CreateEntityByName("prop_physics_override"); + } + else + { + prop = CreateEntityByName("prop_dynamic_override"); + SetEntProp(prop, Prop_Send, "m_nSolidType", solid); + } + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + + g_vecLastEntityAngles[client][0] = vecAngles[0]; + g_vecLastEntityAngles[client][1] = vecAngles[1]; + g_vecLastEntityAngles[client][2] = vecAngles[2]; + DispatchKeyValueVector(prop, "angles", vecAngles); + DispatchSpawn(prop); + TeleportEntity(prop, vecOrigin, NULL_VECTOR, NULL_VECTOR); + g_bSpawned[prop] = true; + g_vecEntityAngles[prop] = vecAngles; + } + else + { + break; + } + } + } + CloseHandle(keyvalues); + PrintToChat(client, "\x03[SM] Succesfully loaded the map data"); + PrintHintText(client, "[SM] If nothing is visible, you probably forgot something during installation"); +} + +public Action CmdRotate(int client, int args) +{ + if(args < 2) + { + PrintToChat(client, "[SM] Usage: sm_prop_rotate [EX: !prop_rotate x 30]"); + return Plugin_Handled; + } + int Object = g_iLastObject[client]; + char arg1[16]; + char arg2[16]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + float vecAngles[3]; + vecAngles[0] = g_vecLastEntityAngles[client][0]; + vecAngles[1] = g_vecLastEntityAngles[client][1]; + vecAngles[2] = g_vecLastEntityAngles[client][2]; + int iAngles = StringToInt(arg2); + if(strcmp(arg1, "x")== 0) + { + vecAngles[0] += iAngles; + } + else if(strcmp(arg1, "y")== 0) + { + vecAngles[1] += iAngles; + } + else if(strcmp(arg1, "z")== 0) + { + vecAngles[2] += iAngles; + } + else + { + PrintToChat(client, "[SM] Invalid Axys (x,y,z are allowed)"); + } + g_vecLastEntityAngles[client] = vecAngles; + TeleportEntity(Object, NULL_VECTOR, vecAngles, NULL_VECTOR); + g_vecEntityAngles[g_iLastObject[client]] = vecAngles; + return Plugin_Handled; +} + +public Action CmdRemoveLast(int client, int args) +{ + DeleteLastProp(client); + return Plugin_Handled; +} + +public Action CmdRemoveLook(int client, int args) +{ + DeleteLookingEntity(client); + return Plugin_Handled; +} + +public Action CmdRemoveAll(int client, int args) +{ + PrintToChat(client, "\x04[SM] %T","Are you sure(Delete All)?",client); + BuildDeleteAllCmd(client); + return Plugin_Handled; +} + +Menu BuildDeleteAllCmd(int client) +{ + Menu menu = new Menu(MenuHandler_cmd_Ask); + menu.SetTitle("%T", "Are you sure?", client); + menu.AddItem("sm_spyes", Translate(client, "%t", "Yes")); + menu.AddItem("sm_spno", Translate(client, "%t", "No")); + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +public int MenuHandler_cmd_Ask(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + char menucmd[256]; + GetMenuItem(menu, param2, menucmd, sizeof(menucmd)); + if(strcmp(menucmd, "sm_spyes")== 0) + { + DeleteAllProps(); + PrintToChat(param1, "[SM] %T", "Successfully deleted all spawned objects", param1); + } + else + { + PrintToChat(param1, "[SM] %T", "Canceled", param1); + } + } + case MenuAction_Cancel: + { + } + case MenuAction_End: + { + delete menu; + } + } +} + +int GetNextMapNumber(char[] FileName) +{ + char FileNameS[256]; + for(int i=1; i <= MAX_PATHS; i++) + { + Format(FileNameS, sizeof(FileNameS), "%s_%i.txt", FileName, i); + if(FileExists(FileNameS)) + { + continue; + } + else + { + return i; + } + } + return -1; +} + +void SpawnObjects() +{ + //if disabled + if(!g_cvarAutoload.BoolValue) + { + return; + } + char KvFileName[256]; + char name[256]; + BuildPath(Path_SM, KvFileName, sizeof(KvFileName), "../stripper/plugin_cache/%s.txt", g_sPath); + LogSpawn("Spawning props from file %s", KvFileName); + if(!FileExists(KvFileName)) + { + LogError("Attempted to load an object file which does not exist (%s)", KvFileName); + LogSpawn("[ERROR] Attempted to load an object file which does not exist (%s)", KvFileName); + return; + } + KeyValues keyvalues = new KeyValues("Objects_Cache"); + keyvalues.ImportFromFile(KvFileName); + keyvalues.Rewind(); + if(keyvalues.JumpToKey("total_cache")) + { + int max = keyvalues.GetNum("total", 0); + if(max <= 0) + { + LogError("No Objects found for the map number cache"); + LogSpawn("[ERROR] No Objects found for the map number cache"); + return; + } + char model[256]; + char class[64]; + float vecOrigin[3]; + float vecAngles[3]; + int solid; + keyvalues.Rewind(); + for(int count=1; count <= max; count++) + { + Format(name, sizeof(name), "object_%i", count); + if(keyvalues.JumpToKey(name)) + { + solid = keyvalues.GetNum("solid"); + keyvalues.GetVector("origin", vecOrigin); + keyvalues.GetVector("angles", vecAngles); + keyvalues.GetString("model", model, sizeof(model)); + keyvalues.GetString("classname", class, sizeof(class)); + int prop = -1; + keyvalues.Rewind(); + if(StrContains(class, "prop_physics") >= 0) + { + prop = CreateEntityByName("prop_physics_override"); + } + else + { + prop = CreateEntityByName("prop_dynamic_override"); + SetEntProp(prop, Prop_Send, "m_nSolidType", solid); + } + DispatchKeyValue(prop, "model", model); + DispatchKeyValue(prop, "targetname", "l4d2_spawn_props_prop"); + + DispatchKeyValueVector(prop, "angles", vecAngles); + DispatchSpawn(prop); + TeleportEntity(prop, vecOrigin, NULL_VECTOR, NULL_VECTOR); + g_bSpawned[prop] = true; + g_vecEntityAngles[prop] = vecAngles; + } + else + { + break; + } + } + } + CloseHandle(keyvalues); +} +void CreateInitFile() +{ + char FileName[256]; + char map[256]; + File file; + GetCurrentMap(map, sizeof(map)); + BuildPath(Path_SM, FileName, sizeof(FileName), "../stripper/plugin_cache/%s_init.txt", map); + + if(!FileExists(FileName)) + { + file = OpenFile(FileName, "a+"); + if(file == null) + { + return; + } + file.WriteLine("//Init file for map %s", map); + file.WriteLine("//DO NOT FORGET TO REPLACE \" FOR QUOTES!"); + file.WriteLine("//"); + file.WriteLine("//The format of the file is:"); + file.WriteLine("//"); + file.WriteLine("// \"coop\" --------> This is the gamemode where the following object list will be loaded"); + file.WriteLine("// {"); + file.WriteLine("// \"total\" \"2\" ---------> This is the total object list availables. Randomly, one will be selected"); + file.WriteLine("// \"path1\" \"c5m2_park_1\" -------------> If the plugin chooses the option 1, the file c5m2_park_1.txt will be loaded"); + file.WriteLine("// \"path2\" \"c5m2_park_3\" -------------> Same if the option is 2"); + file.WriteLine("// }"); + file.WriteLine("//"); + file.WriteLine("// If you have any doubts, please check the example_init.txt file or ask on the plugin topic."); + file.WriteLine("//"); + file.WriteLine(""); + file.WriteLine("\"PathInit\""); + file.WriteLine("{"); + file.WriteLine(" \"coop\""); + file.WriteLine(" {"); + file.WriteLine(" "); + file.WriteLine(" }"); + file.WriteLine(" "); + file.WriteLine(" \"versus\""); + file.WriteLine(" {"); + file.WriteLine(" "); + file.WriteLine(" }"); + file.WriteLine(" "); + file.WriteLine(" \"survival\""); + file.WriteLine(" {"); + file.WriteLine(" "); + file.WriteLine(" }"); + file.WriteLine(" "); + file.WriteLine(" \"scavenge\""); + file.WriteLine(" {"); + file.WriteLine(" "); + file.WriteLine(" }"); + file.WriteLine("}"); + FlushFile(file); + CloseHandle(file); + } +} + +void GetRandomMapPath(char[] MapName, int maxlen) +{ + char KvFileName[256]; + char sMap[128]; + char GameMode[128]; + GetCurrentMap(sMap, sizeof(sMap)); + BuildPath(Path_SM, KvFileName, sizeof(KvFileName), "../stripper/plugin_cache/%s_init.txt", sMap); + if(!FileExists(KvFileName)) + { + LogError("Unable to find the init file!"); + } + else + { + KeyValues keyvalues = new KeyValues("PathInit"); + keyvalues.ImportFromFile(KvFileName); + keyvalues.Rewind(); + ConVar cvarGameMode = FindConVar("mp_gamemode"); + cvarGameMode.GetString(GameMode, sizeof(GameMode)); + if(keyvalues.JumpToKey(GameMode)) + { + char sNumber[11]; + int total_paths = keyvalues.GetNum("total"); + int random = GetRandomInt(1, total_paths); + Format(sNumber, sizeof(sNumber), "path%i", random); + keyvalues.GetString(sNumber, MapName, maxlen); + CloseHandle(keyvalues); + return; + } + else + { + LogError("Unable to find the gamemode"); + Format(MapName, maxlen, "invalid"); + CloseHandle(keyvalues); + return; + } + + } + Format(MapName, maxlen, "invalid"); + return; +} + +public Action CmdMove(int client, int args) +{ + if(args < 2) + { + PrintToChat(client, "[SM] Usage: sm_prop_move [EX: !prop_move x 30]"); + return Plugin_Handled; + } + int Object = g_iLastObject[client]; + char arg1[16]; + char arg2[16]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + float vecPosition[3]; + GetEntPropVector(Object, Prop_Data, "m_vecOrigin", vecPosition); + float flPosition = StringToFloat(arg2); + if(strcmp(arg1, "x")== 0) + { + vecPosition[0] += flPosition; + } + else if(strcmp(arg1, "y")== 0) + { + vecPosition[1] += flPosition; + } + else if(strcmp(arg1, "z")== 0) + { + vecPosition[2] += flPosition; + } + else + { + PrintToChat(client, "[SM] Invalid Axys (x,y,z are allowed)"); + } + g_bGrab[client] = false; + g_bGrabbed[Object] = false; + TeleportEntity(Object, vecPosition, NULL_VECTOR, NULL_VECTOR); + return Plugin_Handled; +} + +public Action CmdSetAngles(int client, int args) +{ + if(args < 3) + { + PrintToChat(client, "[SM] Usage: sm_prop_setang [EX: !prop_setang 30 0 34"); + return Plugin_Handled; + } + int Object = g_iLastObject[client]; + char arg1[16]; + char arg2[16]; + char arg3[16]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + GetCmdArg(3, arg3, sizeof(arg3)); + float vecAngles[3]; + + vecAngles[0] = StringToFloat(arg1); + vecAngles[1] = StringToFloat(arg2); + vecAngles[2] = StringToFloat(arg3); + g_vecLastEntityAngles[client] = vecAngles; + g_vecEntityAngles[Object] = vecAngles; + + g_bGrab[client] = false; + g_bGrabbed[Object] = false; + TeleportEntity(Object, NULL_VECTOR, vecAngles, NULL_VECTOR); + return Plugin_Handled; +} + +public Action CmdSetPosition(int client, int args) +{ + if(args < 3) + { + PrintToChat(client, "[SM] Usage: sm_prop_setpos [EX: !prop_setpos 505 -34 17"); + return Plugin_Handled; + } + int Object = g_iLastObject[client]; + char arg1[16]; + char arg2[16]; + char arg3[16]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + GetCmdArg(3, arg3, sizeof(arg3)); + float vecPosition[3]; + + vecPosition[0] = StringToFloat(arg1); + vecPosition[1] = StringToFloat(arg2); + vecPosition[2] = StringToFloat(arg3); + TeleportEntity(Object, vecPosition, NULL_VECTOR, NULL_VECTOR); + return Plugin_Handled; +} + +/* +////////////////////////////////////////////////////////////////////////////| + Build File Directories | +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| +*/ + +public void BuildFileDirectories() +{ + for(int Num; Num < sizeof(FolderNames); Num++) + { + if(!DirExists(FolderNames[Num])) + { + CreateDirectory(FolderNames[Num], 509); + } + } +} + +stock char[] Translate(int client, const char[] format, any ...) +{ + char buffer[192]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), format, 3); + return buffer; +} \ No newline at end of file diff --git a/scripting/l4d2_turret.sp b/scripting/l4d2_turret.sp index 15c082f..7361636 100644 --- a/scripting/l4d2_turret.sp +++ b/scripting/l4d2_turret.sp @@ -263,6 +263,7 @@ int AddMountedGun(int entity, MountedGun type) { DispatchKeyValue(poseCtrl, "targetname", buffer); DispatchKeyValue(poseCtrl, "PoseParameterName", "MiniGun_Horizontal"); DispatchKeyValue(poseCtrl, "CycleFrequency", "0"); + DispatchKeyValue(poseCtrl, "FModRate", "0"); DispatchSpawn(poseCtrl); SetParent(poseCtrl, entity); MTurret[MTurretCount].poseController = EntIndexToEntRef(poseCtrl); @@ -669,9 +670,14 @@ public Action Timer_Think(Handle h) { targetPos[2] += 40.0; // hit infected better GetAngles(pos, targetPos, angles); float angle = 0.5 + (angles[1] - turretAngles[1]) / FLOAT_PI; - SetPoseControllerParameter(MTurret[i].poseController, "MiniGun_Vertical", -90.0, 90.0, angle); - angle = 0.5 + (angles[0] - turretAngles[0]) / FLOAT_PI; - SetPoseControllerParameter(MTurret[i].poseController, "MiniGun_Horizontal", -90.0, 90.0, angle); + SetVariantString("Minigun_Horizontal"); + AcceptEntityInput(MTurret[i].poseController, "SetPoseParameterName"); + SetVariantFloat(angle); + AcceptEntityInput(MTurret[i].poseController, "SetPoseValue"); + PrintToConsoleAll("angle:%f", angle); + // SetPoseControllerParameter(MTurret[i].poseController, "MiniGun_Vertical", -90.0, 90.0, angle); + // angle = 0.5 + (angles[0] - turretAngles[0]) / FLOAT_PI; + // SetPoseControllerParameter(MTurret[i].poseController, "MiniGun_Horizontal", -90.0, 90.0, angle); // SetPoseParameter(MTurret[i].entity, 0, -90.0, 90.0, angles[0]); // SetPoseParameter(MTurret[i].entity, 1, -90.0, 90.0, angles[1]); TR_TraceRay(pos, targetPos, 0, RayType_EndPoint);