mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-05 21:03:20 +00:00
644 lines
No EOL
20 KiB
SourcePawn
644 lines
No EOL
20 KiB
SourcePawn
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<buildType>(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;
|
|
} |