mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-06 21:33:20 +00:00
Update
This commit is contained in:
parent
44733c3b14
commit
a97e151816
14 changed files with 5830 additions and 843 deletions
|
@ -1,6 +1,7 @@
|
||||||
int BUILDER_COLOR[4] = { 0, 255, 0, 235 };
|
int BUILDER_COLOR[4] = { 0, 255, 0, 235 };
|
||||||
int GLOW_BLUE[4] = { 3, 148, 252 };
|
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_WHITE[4] = { 255, 255, 255, 255 };
|
||||||
int GLOW_GREEN[4] = { 3, 252, 53 };
|
int GLOW_GREEN[4] = { 3, 252, 53 };
|
||||||
float ORIGIN_SIZE[3] = { 2.0, 2.0, 2.0 };
|
float ORIGIN_SIZE[3] = { 2.0, 2.0, 2.0 };
|
||||||
|
@ -46,9 +47,14 @@ char COLOR_INDEX[4] = "RGBA";
|
||||||
ArrayList createdWalls;
|
ArrayList createdWalls;
|
||||||
|
|
||||||
enum struct WallBuilderData {
|
enum struct WallBuilderData {
|
||||||
|
char classname[32];
|
||||||
|
char data[32];
|
||||||
|
|
||||||
float origin[3];
|
float origin[3];
|
||||||
float mins[3];
|
float prevOrigin[3];
|
||||||
float angles[3];
|
float angles[3];
|
||||||
|
float prevAngles[3];
|
||||||
|
float mins[3];
|
||||||
float size[3];
|
float size[3];
|
||||||
int color[4];
|
int color[4];
|
||||||
int colorIndex;
|
int colorIndex;
|
||||||
|
@ -58,6 +64,7 @@ enum struct WallBuilderData {
|
||||||
float moveDistance;
|
float moveDistance;
|
||||||
int entity;
|
int entity;
|
||||||
bool hasCollision;
|
bool hasCollision;
|
||||||
|
bool hasCollisionRotate;
|
||||||
|
|
||||||
editMode mode;
|
editMode mode;
|
||||||
buildType buildType;
|
buildType buildType;
|
||||||
|
@ -70,6 +77,7 @@ enum struct WallBuilderData {
|
||||||
RemoveEntity(this.entity);
|
RemoveEntity(this.entity);
|
||||||
}
|
}
|
||||||
this.entity = INVALID_ENT_REFERENCE;
|
this.entity = INVALID_ENT_REFERENCE;
|
||||||
|
this.data[0] = '\0';
|
||||||
this.size[0] = this.size[1] = this.size[2] = 5.0;
|
this.size[0] = this.size[1] = this.size[2] = 5.0;
|
||||||
this.angles[0] = this.angles[1] = this.angles[2] = 0.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;
|
this.color[0] = this.color[1] = this.color[2] = this.color[3] = 255;
|
||||||
|
@ -77,8 +85,10 @@ enum struct WallBuilderData {
|
||||||
this.axis = 1;
|
this.axis = 1;
|
||||||
this.moveDistance = 200.0;
|
this.moveDistance = 200.0;
|
||||||
this.hasCollision = true;
|
this.hasCollision = true;
|
||||||
|
this.hasCollisionRotate = false;
|
||||||
this.flags = Edit_None;
|
this.flags = Edit_None;
|
||||||
this.buildType = Build_Solid;
|
this.buildType = Build_Solid;
|
||||||
|
this.classname[0] = '\0';
|
||||||
this.CalculateMins();
|
this.CalculateMins();
|
||||||
this.SetMode(INACTIVE);
|
this.SetMode(INACTIVE);
|
||||||
if(initial) {
|
if(initial) {
|
||||||
|
@ -130,6 +140,10 @@ enum struct WallBuilderData {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetData(const char[] data) {
|
||||||
|
strcopy(this.data, sizeof(this.data), data);
|
||||||
|
}
|
||||||
|
|
||||||
void CycleMode(int client, float tick) {
|
void CycleMode(int client, float tick) {
|
||||||
if(tick - cmdThrottle[client] <= 0.25) return;
|
if(tick - cmdThrottle[client] <= 0.25) return;
|
||||||
int flags = GetEntityFlags(client) & ~FL_FROZEN;
|
int flags = GetEntityFlags(client) & ~FL_FROZEN;
|
||||||
|
@ -157,7 +171,6 @@ enum struct WallBuilderData {
|
||||||
}
|
}
|
||||||
case FREELOOK: {
|
case FREELOOK: {
|
||||||
this.mode = MOVE_ORIGIN;
|
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]);
|
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;
|
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) {
|
void CycleAxis(int client, float tick) {
|
||||||
if(tick - cmdThrottle[client] <= 0.15) return;
|
if(tick - cmdThrottle[client] <= 0.15) return;
|
||||||
if(this.axis == 0) {
|
if(this.axis == 0) {
|
||||||
|
@ -199,9 +222,9 @@ enum struct WallBuilderData {
|
||||||
case 90: this.snapAngle = 1;
|
case 90: this.snapAngle = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.angles[0] = SnapTo(this.angles[0], 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[1] = SnapTo(this.angles[1], float(this.snapAngle));
|
||||||
this.angles[2] = SnapTo(this.angles[2], float(this.snapAngle));
|
// this.angles[2] = SnapTo(this.angles[2], float(this.snapAngle));
|
||||||
|
|
||||||
if(this.snapAngle == 1)
|
if(this.snapAngle == 1)
|
||||||
PrintToChat(client, "\x04[Editor]\x01 Rotate Snap Degrees: \x04(OFF)\x01", this.snapAngle);
|
PrintToChat(client, "\x04[Editor]\x01 Rotate Snap Degrees: \x04(OFF)\x01", this.snapAngle);
|
||||||
|
@ -220,7 +243,9 @@ enum struct WallBuilderData {
|
||||||
|
|
||||||
void CycleBuildType(int client) {
|
void CycleBuildType(int client) {
|
||||||
// No tick needed, is handled externally
|
// 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;
|
this.buildType = Build_Solid;
|
||||||
PrintToChat(client, "\x04[Editor]\x01 Spawn as: \x05Solid\x01");
|
PrintToChat(client, "\x04[Editor]\x01 Spawn as: \x05Solid\x01");
|
||||||
} else if(this.buildType == Build_Solid) {
|
} else if(this.buildType == Build_Solid) {
|
||||||
|
@ -302,22 +327,46 @@ enum struct WallBuilderData {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _FinishPreview(int& entity) {
|
int _CreateWeapon() {
|
||||||
entity = -1;
|
int entity = -1;
|
||||||
if(this.buildType == Build_Physics)
|
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");
|
entity = CreateEntityByName("prop_physics");
|
||||||
else
|
else
|
||||||
entity = CreateEntityByName("prop_dynamic");
|
entity = CreateEntityByName("prop_dynamic_override");
|
||||||
if(entity == -1) return false;
|
if(entity == -1) return false;
|
||||||
|
|
||||||
char model[128];
|
char model[128];
|
||||||
GetEntPropString(this.entity, Prop_Data, "m_ModelName", model, sizeof(model));
|
GetEntPropString(this.entity, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||||
DispatchKeyValue(entity, "model", model);
|
DispatchKeyValue(entity, "model", model);
|
||||||
DispatchKeyValue(entity, "targetname", "prop_preview");
|
|
||||||
if(this.buildType == Build_NonSolid)
|
if(this.buildType == Build_NonSolid)
|
||||||
DispatchKeyValue(entity, "solid", "0");
|
DispatchKeyValue(entity, "solid", "0");
|
||||||
else
|
else
|
||||||
DispatchKeyValue(entity, "solid", "6");
|
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);
|
TeleportEntity(entity, this.origin, this.angles, NULL_VECTOR);
|
||||||
if(!DispatchSpawn(entity)) {
|
if(!DispatchSpawn(entity)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -351,8 +400,6 @@ enum struct WallBuilderData {
|
||||||
DispatchKeyValue(entity, "solid", "6");
|
DispatchKeyValue(entity, "solid", "6");
|
||||||
|
|
||||||
DispatchSpawn(entity);
|
DispatchSpawn(entity);
|
||||||
// SetEntProp(entity, Prop_Send, "m_CollisionGroup", 1);
|
|
||||||
// SetEntProp(entity, Prop_Send, "m_nSolidType", 6);
|
|
||||||
TeleportEntity(entity, this.origin, this.angles, NULL_VECTOR);
|
TeleportEntity(entity, this.origin, this.angles, NULL_VECTOR);
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
this.flags |= Edit_Copy;
|
this.flags |= Edit_Copy;
|
||||||
|
@ -364,12 +411,62 @@ enum struct WallBuilderData {
|
||||||
this.flags |= Edit_WallCreator;
|
this.flags |= Edit_WallCreator;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PreviewModel(const char[] model) {
|
bool PreviewWeapon(const char[] classname) {
|
||||||
// If last entity was preview, kill it
|
return false;
|
||||||
PrecacheModel(model);
|
int entity;
|
||||||
|
// Melee weapons don't have weapon_ prefix
|
||||||
this.Reset();
|
this.Reset();
|
||||||
int entity = CreateEntityByName("prop_dynamic");
|
this.SetData(classname);
|
||||||
if(entity == -1) return false;
|
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, "model", model);
|
||||||
DispatchKeyValue(entity, "targetname", "prop_preview");
|
DispatchKeyValue(entity, "targetname", "prop_preview");
|
||||||
DispatchKeyValue(entity, "solid", "0");
|
DispatchKeyValue(entity, "solid", "0");
|
||||||
|
@ -377,6 +474,7 @@ enum struct WallBuilderData {
|
||||||
DispatchKeyValue(entity, "renderamt", "200");
|
DispatchKeyValue(entity, "renderamt", "200");
|
||||||
DispatchKeyValue(entity, "rendermode", "1");
|
DispatchKeyValue(entity, "rendermode", "1");
|
||||||
if(!DispatchSpawn(entity)) {
|
if(!DispatchSpawn(entity)) {
|
||||||
|
PrintToServer("Failed to spawn");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
|
@ -390,6 +488,8 @@ enum struct WallBuilderData {
|
||||||
this.Reset();
|
this.Reset();
|
||||||
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin);
|
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin);
|
||||||
GetEntPropVector(entity, Prop_Send, "m_angRotation", this.angles);
|
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_vecMins", this.mins);
|
||||||
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", this.size);
|
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", this.size);
|
||||||
if(!makeCopy) {
|
if(!makeCopy) {
|
||||||
|
@ -402,62 +502,15 @@ enum struct WallBuilderData {
|
||||||
// Delete any copies:
|
// Delete any copies:
|
||||||
if(this.flags & Edit_Copy || this.flags & Edit_Preview) {
|
if(this.flags & Edit_Copy || this.flags & Edit_Preview) {
|
||||||
RemoveEntity(this.entity);
|
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);
|
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];
|
WallBuilderData Editor[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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
Action OnWallClicked(int entity, int activator, int caller, UseType type, float value) {
|
Action OnWallClicked(int entity, int activator, int caller, UseType type, float value) {
|
||||||
int wallId = FindWallId(entity);
|
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?
|
// TODO: Stacker, copy tool, new command?
|
||||||
public Action Command_MakeWall(int client, int args) {
|
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");
|
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 {
|
} else {
|
||||||
WallBuilder[client].StartWall();
|
Editor[client].StartWall();
|
||||||
if(args > 0) {
|
if(args > 0) {
|
||||||
// Get values for X, Y and Z axis (defaulting to 1.0):
|
// Get values for X, Y and Z axis (defaulting to 1.0):
|
||||||
char arg2[8];
|
char arg2[8];
|
||||||
|
@ -487,7 +540,7 @@ public Action Command_MakeWall(int client, int args) {
|
||||||
if(StringToFloatEx(arg2, value) == 0) {
|
if(StringToFloatEx(arg2, value) == 0) {
|
||||||
value = 1.0;
|
value = 1.0;
|
||||||
}
|
}
|
||||||
WallBuilder[client].size[i] = value;
|
Editor[client].size[i] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
float rot[3];
|
float rot[3];
|
||||||
|
@ -495,23 +548,24 @@ public Action Command_MakeWall(int client, int args) {
|
||||||
// Flip X and Y depending on rotation
|
// Flip X and Y depending on rotation
|
||||||
// TODO: Validate
|
// TODO: Validate
|
||||||
if(rot[2] > 45 && rot[2] < 135 || rot[2] > -135 && rot[2] < -45) {
|
if(rot[2] > 45 && rot[2] < 135 || rot[2] > -135 && rot[2] < -45) {
|
||||||
float temp = WallBuilder[client].size[0];
|
float temp = Editor[client].size[0];
|
||||||
WallBuilder[client].size[0] = WallBuilder[client].size[1];
|
Editor[client].size[0] = Editor[client].size[1];
|
||||||
WallBuilder[client].size[1] = temp;
|
Editor[client].size[1] = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
WallBuilder[client].CalculateMins();
|
Editor[client].CalculateMins();
|
||||||
}
|
}
|
||||||
|
|
||||||
WallBuilder[client].SetMode(SCALE);
|
Editor[client].SetMode(SCALE);
|
||||||
GetCursorLimited(client, 100.0, WallBuilder[client].origin, Filter_IgnorePlayer);
|
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 New Wall Started. End with \x05/wall build\x01 or \x04/wall cancel\x01");
|
||||||
PrintToChat(client, "\x04[Editor]\x01 Mode: \x05Scale\x01");
|
PrintToChat(client, "\x04[Editor]\x01 Mode: \x05Scale\x01");
|
||||||
}
|
}
|
||||||
return Plugin_Handled;
|
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) {
|
if(args == 0) {
|
||||||
PrintToChat(client, "\x04[Editor]\x01 Created Walls: \x05%d\x01", createdWalls.Length);
|
PrintToChat(client, "\x04[Editor]\x01 Created Walls: \x05%d\x01", createdWalls.Length);
|
||||||
for(int i = 1; i <= createdWalls.Length; i++) {
|
for(int i = 1; i <= createdWalls.Length; i++) {
|
||||||
|
@ -528,7 +582,7 @@ public Action Command_ManageWalls(int client, int args) {
|
||||||
SetEntityFlags(client, flags);
|
SetEntityFlags(client, flags);
|
||||||
|
|
||||||
int entity;
|
int entity;
|
||||||
CompleteType result = WallBuilder[client].Create(entity);
|
CompleteType result = Editor[client].Create(entity);
|
||||||
switch(result) {
|
switch(result) {
|
||||||
case Complete_WallSuccess: {
|
case Complete_WallSuccess: {
|
||||||
if(entity > 0)
|
if(entity > 0)
|
||||||
|
@ -548,10 +602,10 @@ public Action Command_ManageWalls(int client, int args) {
|
||||||
} else if(StrEqual(arg1, "cancel")) {
|
} else if(StrEqual(arg1, "cancel")) {
|
||||||
int flags = GetEntityFlags(client) & ~FL_FROZEN;
|
int flags = GetEntityFlags(client) & ~FL_FROZEN;
|
||||||
SetEntityFlags(client, flags);
|
SetEntityFlags(client, flags);
|
||||||
WallBuilder[client].Cancel();
|
Editor[client].Cancel();
|
||||||
if(WallBuilder[client].flags & Edit_Preview)
|
if(Editor[client].flags & Edit_Preview)
|
||||||
PrintToChat(client, "\x04[Editor]\x01 Prop Spawer: \x04Done\x01");
|
PrintToChat(client, "\x04[Editor]\x01 Prop Spawer: \x04Cancelled\x01");
|
||||||
else if(WallBuilder[client].flags & Edit_WallCreator) {
|
else if(Editor[client].flags & Edit_WallCreator) {
|
||||||
PrintToChat(client, "\x04[Editor]\x01 Wall Creation: \x04Cancelled\x01");
|
PrintToChat(client, "\x04[Editor]\x01 Wall Creation: \x04Cancelled\x01");
|
||||||
} else {
|
} else {
|
||||||
PrintToChat(client, "\x04[Editor]\x01 Entity Edit: \x04Cancelled\x01");
|
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")) {
|
} else if(StrEqual(arg1, "export")) {
|
||||||
// TODO: support exp #id
|
// TODO: support exp #id
|
||||||
float origin[3], angles[3], size[3];
|
float origin[3], angles[3], size[3];
|
||||||
if(WallBuilder[client].IsActive()) {
|
if(Editor[client].IsActive()) {
|
||||||
origin = WallBuilder[client].origin;
|
origin = Editor[client].origin;
|
||||||
angles = WallBuilder[client].angles;
|
angles = Editor[client].angles;
|
||||||
size = WallBuilder[client].size;
|
size = Editor[client].size;
|
||||||
Export(client, arg2, WallBuilder[client].entity, origin, angles, size);
|
Export(client, arg2, Editor[client].entity, origin, angles, size);
|
||||||
} else {
|
} else {
|
||||||
int id = GetWallId(client, arg2);
|
int id = GetWallId(client, arg2);
|
||||||
if(id == -1) return Plugin_Handled;
|
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);
|
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", size);
|
||||||
Export(client, arg2, entity, origin, angles, size);
|
Export(client, arg2, entity, origin, angles, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else if(StrEqual(arg1, "delete")) {
|
} else if(StrEqual(arg1, "delete")) {
|
||||||
if(WallBuilder[client].IsActive() && args == 1) {
|
if(Editor[client].IsActive() && args == 1) {
|
||||||
int entity = WallBuilder[client].entity;
|
int entity = Editor[client].entity;
|
||||||
if(IsValidEntity(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 <id/all>");
|
PrintToChat(client, "\x04[Editor]\x01 You are not editing any existing entity, use \x05/wall cancel\x01 to stop or \x05/wall delete <id/all>");
|
||||||
} else if(entity > MaxClients) {
|
} else if(entity > MaxClients) {
|
||||||
RemoveEntity(entity);
|
RemoveEntity(entity);
|
||||||
WallBuilder[client].Reset();
|
Editor[client].Reset();
|
||||||
PrintToChat(client, "\x04[Editor]\x01 Deleted current entity");
|
PrintToChat(client, "\x04[Editor]\x01 Deleted current entity");
|
||||||
} else {
|
} else {
|
||||||
PrintToChat(client, "\x04[Editor]\x01 Cannot delete player entities.");
|
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);
|
int id = GetWallId(client, arg2);
|
||||||
if(id > -1) {
|
if(id > -1) {
|
||||||
int entity = GetWallEntity(id);
|
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 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");
|
PrintToChat(client, "\x04[Editor]\x01 Mode: \x05Scale\x01");
|
||||||
}
|
}
|
||||||
} else if(StrEqual(arg1, "edite") || (arg1[0] == 'c' && arg1[1] == 'u')) {
|
} else if(StrEqual(arg1, "edite") || (arg1[0] == 'c' && arg1[1] == 'u')) {
|
||||||
int index = GetLookingEntity(client, Filter_ValidHats); //GetClientAimTarget(client, false);
|
int index = GetLookingEntity(client, Filter_ValidHats); //GetClientAimTarget(client, false);
|
||||||
if(index > 0) {
|
if(index > 0) {
|
||||||
WallBuilder[client].Import(index, false, MOVE_ORIGIN);
|
Editor[client].Import(index, false, MOVE_ORIGIN);
|
||||||
char classname[32];
|
char classname[32];
|
||||||
char targetname[32];
|
char targetname[32];
|
||||||
GetEntityClassname(index, classname, sizeof(classname));
|
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");
|
ReplyToCommand(client, "\x04[Editor]\x01 Invalid or non existent entity");
|
||||||
}
|
}
|
||||||
} else if(StrEqual(arg1, "copy")) {
|
} else if(StrEqual(arg1, "copy")) {
|
||||||
if(WallBuilder[client].IsActive()) {
|
if(Editor[client].IsActive()) {
|
||||||
int oldEntity = WallBuilder[client].entity;
|
int oldEntity = Editor[client].entity;
|
||||||
if(oldEntity == INVALID_ENT_REFERENCE) {
|
if(oldEntity == INVALID_ENT_REFERENCE) {
|
||||||
PrintToChat(client, "\x04[Editor]\x01 Finish editing your wall first: \x05/wall done\x01 or \x04/wall cancel\x01");
|
PrintToChat(client, "\x04[Editor]\x01 Finish editing your wall first: \x05/wall done\x01 or \x04/wall cancel\x01");
|
||||||
} else {
|
} 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);
|
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 {
|
} else {
|
||||||
int id = GetWallId(client, arg2);
|
int id = GetWallId(client, arg2);
|
||||||
if(id > -1) {
|
if(id > -1) {
|
||||||
int entity = GetWallEntity(id);
|
int entity = GetWallEntity(id);
|
||||||
WallBuilder[client].Import(entity, true);
|
Editor[client].Import(entity, true);
|
||||||
GetCursorLimited(client, 100.0, WallBuilder[client].origin, Filter_IgnorePlayer);
|
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 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");
|
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) {
|
void DeleteWall(int id) {
|
||||||
GlowWall(id, GLOW_RED);
|
GlowWall(id, GLOW_RED_ALPHA);
|
||||||
int ref = GetWallEntity(id);
|
int ref = GetWallEntity(id);
|
||||||
if(IsValidEntity(ref)) {
|
if(IsValidEntity(ref)) {
|
||||||
RemoveEntity(ref);
|
RemoveEntity(ref);
|
|
@ -326,9 +326,9 @@ Action Command_DoAHat(int client, int args) {
|
||||||
}
|
}
|
||||||
} else if(arg[0] == 'd') {
|
} else if(arg[0] == 'd') {
|
||||||
// Use the new wall editor
|
// Use the new wall editor
|
||||||
WallBuilder[client].Reset();
|
Editor[client].Reset();
|
||||||
WallBuilder[client].entity = EntIndexToEntRef(entity);
|
Editor[client].entity = EntIndexToEntRef(entity);
|
||||||
WallBuilder[client].SetMode(MOVE_ORIGIN);
|
Editor[client].SetMode(MOVE_ORIGIN);
|
||||||
PrintToChat(client, "\x04[Hats] \x01Beta Prop Mover active for \x04%d", entity);
|
PrintToChat(client, "\x04[Hats] \x01Beta Prop Mover active for \x04%d", entity);
|
||||||
} else {
|
} else {
|
||||||
PrintToChat(client, "[Hats] Restored hat to its original position.");
|
PrintToChat(client, "[Hats] Restored hat to its original position.");
|
||||||
|
@ -349,7 +349,7 @@ Action Command_DoAHat(int client, int args) {
|
||||||
if(entity <= 0) {
|
if(entity <= 0) {
|
||||||
PrintCenterText(client, "[Hats] No entity found");
|
PrintCenterText(client, "[Hats] No entity found");
|
||||||
return Plugin_Handled;
|
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
|
// Prevent making an entity you editing a hat
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
} else if(!isForced && cvar_sm_hats_max_distance.FloatValue > 0.0 && entity >= MaxClients) {
|
} 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<int>(HatConfig_InfectedHats)) {
|
} else if(GetClientTeam(entity) != 2 && ~cvar_sm_hats_flags.IntValue & view_as<int>(HatConfig_InfectedHats)) {
|
||||||
PrintToChat(client, "[Hats] Cannot make enemy a hat... it's dangerous");
|
PrintToChat(client, "[Hats] Cannot make enemy a hat... it's dangerous");
|
||||||
return Plugin_Handled;
|
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
|
// Old check left in in case you hatting child entity
|
||||||
PrintToChat(client, "[Hats] You are currently editing this entity");
|
PrintToChat(client, "[Hats] You are currently editing this entity");
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
|
@ -569,7 +569,7 @@ void ClearHat(int i, bool restore = false) {
|
||||||
// if(HasEntProp(entity, Prop_Send, "m_flModelScale"))
|
// if(HasEntProp(entity, Prop_Send, "m_flModelScale"))
|
||||||
// SetEntPropFloat(entity, Prop_Send, "m_flModelScale", 1.0);
|
// SetEntPropFloat(entity, Prop_Send, "m_flModelScale", 1.0);
|
||||||
SetEntProp(modifyEntity, Prop_Send, "m_CollisionGroup", hatData[i].collisionGroup);
|
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);
|
SetEntProp(modifyEntity, Prop_Send, "movetype", hatData[i].moveType);
|
||||||
|
|
||||||
hatData[i].entity = INVALID_ENT_REFERENCE;
|
hatData[i].entity = INVALID_ENT_REFERENCE;
|
||||||
|
@ -667,7 +667,7 @@ bool CanHatBePlaced(int client, const float pos[3]) {
|
||||||
int spawnFlags = L4D_GetNavArea_SpawnAttributes(nav) ;
|
int spawnFlags = L4D_GetNavArea_SpawnAttributes(nav) ;
|
||||||
if(spawnFlags & NAV_SPAWN_CHECKPOINT) {
|
if(spawnFlags & NAV_SPAWN_CHECKPOINT) {
|
||||||
PrintToServer("\"%L\" tried to place hat in saferoom, denied.", client);
|
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;
|
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);
|
L4D2_SetEntityGlow(modifyEntity, L4D2Glow_Constant, 0, 0, color, false);
|
||||||
#endif
|
#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, "m_CollisionGroup", 1);
|
||||||
SetEntProp(modifyEntity, Prop_Send, "movetype", MOVETYPE_NONE);
|
SetEntProp(modifyEntity, Prop_Send, "movetype", MOVETYPE_NONE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<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;
|
|
||||||
}
|
|
145
scripting/include/hats/props/base.sp
Normal file
145
scripting/include/hats/props/base.sp
Normal file
|
@ -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<ItemData>, false: items is ArrayList<CategoryData>
|
||||||
|
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<buildType>(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<CategoryData>
|
||||||
|
ArrayList g_spawnedItems; // ArrayList(block=2)<entRef, [creator]>
|
||||||
|
ArrayList g_savedItems; // ArrayList<entRef>
|
||||||
|
StringMap g_recentItems; // Key: model[128], value: RecentEntry
|
||||||
|
|
||||||
|
#include <hats/props/methods.sp>
|
||||||
|
#include <hats/props/cmd.sp>
|
||||||
|
#include <hats/props/menu_handlers.sp>
|
||||||
|
#include <hats/props/menu_methods.sp>
|
63
scripting/include/hats/props/cmd.sp
Normal file
63
scripting/include/hats/props/cmd.sp
Normal file
|
@ -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 <search query>");
|
||||||
|
PrintToConsole(client, "edit <last/#index>");
|
||||||
|
PrintToConsole(client, "del <last/#index/tool>");
|
||||||
|
PrintToConsole(client, "add <cursor/tool>");
|
||||||
|
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;
|
||||||
|
}
|
239
scripting/include/hats/props/menu_handlers.sp
Normal file
239
scripting/include/hats/props/menu_handlers.sp
Normal file
|
@ -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;
|
||||||
|
}
|
174
scripting/include/hats/props/menu_methods.sp
Normal file
174
scripting/include/hats/props/menu_methods.sp
Normal file
|
@ -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;
|
||||||
|
}
|
479
scripting/include/hats/props/methods.sp
Normal file
479
scripting/include/hats/props/methods.sp
Normal file
|
@ -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<ItemData> 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;
|
||||||
|
}
|
|
@ -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) {
|
stock void GlowEntity(int entity, float lifetime = 10.0, int glowColor[3] = _glowColor) {
|
||||||
L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, glowColor, false);
|
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) {
|
Action Timer_ClearGlow(Handle h, int ref) {
|
||||||
|
|
|
@ -298,7 +298,7 @@ public Action L4D2_CGasCan_EventKilled(int gascan, int &inflictor, int &attacker
|
||||||
float activatorFlow = L4D2Direct_GetFlowDistance(attacker);
|
float activatorFlow = L4D2Direct_GetFlowDistance(attacker);
|
||||||
GroupResult result;
|
GroupResult result;
|
||||||
PrintToConsoleAll("[CC] Gascan Shot by %N", attacker);
|
PrintToConsoleAll("[CC] Gascan Shot by %N", attacker);
|
||||||
ComputeGroups(result, activatorFlow);
|
// ComputeGroups(result, activatorFlow);
|
||||||
|
|
||||||
AdminId admin = GetUserAdmin(attacker);
|
AdminId admin = GetUserAdmin(attacker);
|
||||||
if(admin != INVALID_ADMIN_ID && admin.HasFlag(Admin_Custom1)) {
|
if(admin != INVALID_ADMIN_ID && admin.HasFlag(Admin_Custom1)) {
|
||||||
|
|
|
@ -1397,12 +1397,7 @@ void SetExtraKits(int playerCount) {
|
||||||
if(GetRandomFloat() < 0.3 && averageTeamHP <= 80.0) ++extraPlayers;
|
if(GetRandomFloat() < 0.3 && averageTeamHP <= 80.0) ++extraPlayers;
|
||||||
|
|
||||||
|
|
||||||
//If hAddExtraKits TRUE: Append to previous, FALSE: Overwrite
|
g_extraKitsAmount += extraPlayers;
|
||||||
if(hAddExtraKits.BoolValue)
|
|
||||||
g_extraKitsAmount += extraPlayers;
|
|
||||||
else
|
|
||||||
g_extraKitsAmount = extraPlayers;
|
|
||||||
|
|
||||||
g_extraKitsStart = g_extraKitsAmount;
|
g_extraKitsStart = g_extraKitsAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,20 +38,16 @@ ConVar cvar_sm_hats_max_distance;
|
||||||
|
|
||||||
TopMenu g_topMenu;
|
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];
|
char g_currentMap[64];
|
||||||
|
|
||||||
#include <hats/walls.sp>
|
//int g_markedMode
|
||||||
|
|
||||||
|
#include <hats/editor.sp>
|
||||||
#include <hats/hats.sp>
|
#include <hats/hats.sp>
|
||||||
#include <hats/hat_presets.sp>
|
#include <hats/hat_presets.sp>
|
||||||
#include <hats/props.sp>
|
#include <hats/props/base.sp>
|
||||||
|
|
||||||
public Plugin myinfo =
|
public Plugin myinfo = {
|
||||||
{
|
|
||||||
name = "L4D2 Hats",
|
name = "L4D2 Hats",
|
||||||
author = "jackzmc",
|
author = "jackzmc",
|
||||||
description = "",
|
description = "",
|
||||||
|
@ -81,8 +77,8 @@ public void OnPluginStart() {
|
||||||
RegConsoleCmd("sm_hat", Command_DoAHat, "Hats");
|
RegConsoleCmd("sm_hat", Command_DoAHat, "Hats");
|
||||||
RegAdminCmd("sm_hatf", Command_DoAHat, ADMFLAG_ROOT, "Hats");
|
RegAdminCmd("sm_hatf", Command_DoAHat, ADMFLAG_ROOT, "Hats");
|
||||||
RegAdminCmd("sm_mkwall", Command_MakeWall, ADMFLAG_CHEATS);
|
RegAdminCmd("sm_mkwall", Command_MakeWall, ADMFLAG_CHEATS);
|
||||||
RegAdminCmd("sm_walls", Command_ManageWalls, ADMFLAG_CHEATS);
|
RegAdminCmd("sm_edit", Command_Editor, ADMFLAG_CHEATS);
|
||||||
RegAdminCmd("sm_wall", Command_ManageWalls, ADMFLAG_CHEATS);
|
RegAdminCmd("sm_wall", Command_Editor, ADMFLAG_CHEATS);
|
||||||
RegAdminCmd("sm_prop", Command_Props, ADMFLAG_CHEATS);
|
RegAdminCmd("sm_prop", Command_Props, ADMFLAG_CHEATS);
|
||||||
RegConsoleCmd("sm_hatp", Command_DoAHatPreset);
|
RegConsoleCmd("sm_hatp", Command_DoAHatPreset);
|
||||||
|
|
||||||
|
@ -110,7 +106,7 @@ public void OnPluginStart() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 1; i <= MaxClients; i++) {
|
for(int i = 1; i <= MaxClients; i++) {
|
||||||
WallBuilder[i].Reset(true);
|
Editor[i].Reset(true);
|
||||||
hatData[i].yeetGroundTimer = null;
|
hatData[i].yeetGroundTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +129,7 @@ public void OnLibraryRemoved(const char[] name) {
|
||||||
public void OnEnterSaferoom(Event event, const char[] name, bool dontBroadcast) {
|
public void OnEnterSaferoom(Event event, const char[] name, bool dontBroadcast) {
|
||||||
int userid = event.GetInt("userid");
|
int userid = event.GetInt("userid");
|
||||||
int client = GetClientOfUserId(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;
|
inSaferoom[client] = true;
|
||||||
if(cvar_sm_hats_flags.IntValue & view_as<int>(HatConfig_NoSaferoomHats)) {
|
if(cvar_sm_hats_flags.IntValue & view_as<int>(HatConfig_NoSaferoomHats)) {
|
||||||
if(HasHat(client) && !HasFlag(client, HAT_PRESET)) {
|
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]) {
|
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();
|
float tick = GetGameTime();
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
@ -567,13 +564,52 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
// OnPlayerRunCmd :: ENTITY EDITOR
|
// 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) {
|
if(buttons & IN_USE && buttons & IN_RELOAD) {
|
||||||
ClientCommand(client, "sm_wall done");
|
ClientCommand(client, "sm_wall done");
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
bool allowMove = true;
|
bool allowMove = true;
|
||||||
switch(WallBuilder[client].mode) {
|
switch(Editor[client].mode) {
|
||||||
case MOVE_ORIGIN: {
|
case MOVE_ORIGIN: {
|
||||||
|
|
||||||
SetWeaponDelay(client, 0.5);
|
SetWeaponDelay(client, 0.5);
|
||||||
|
@ -581,34 +617,42 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
||||||
bool isRotate;
|
bool isRotate;
|
||||||
int flags = GetEntityFlags(client);
|
int flags = GetEntityFlags(client);
|
||||||
if(buttons & IN_USE && ~buttons & IN_ZOOM) {
|
if(buttons & IN_USE && ~buttons & IN_ZOOM) {
|
||||||
|
if(!g_inRotate[client]) {
|
||||||
|
g_inRotate[client] = true;
|
||||||
|
}
|
||||||
if(buttons & IN_SPEED) {
|
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 {
|
} 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;
|
isRotate = true;
|
||||||
SetEntityFlags(client, flags |= FL_FROZEN);
|
SetEntityFlags(client, flags |= FL_FROZEN);
|
||||||
if(buttons & IN_ATTACK) WallBuilder[client].CycleAxis(client, tick);
|
if(buttons & IN_ATTACK) Editor[client].CycleAxis(client, tick);
|
||||||
else if(buttons & IN_ATTACK2) WallBuilder[client].CycleSnapAngle(client, tick);
|
else if(buttons & IN_ATTACK2) Editor[client].CycleSnapAngle(client, tick);
|
||||||
|
|
||||||
// Rotation control:
|
// Rotation control:
|
||||||
if(tick - cmdThrottle[client] > 0.20) {
|
if(tick - cmdThrottle[client] > 0.20) {
|
||||||
if(WallBuilder[client].axis == 0) {
|
// Turn off rotate when player wants rotate
|
||||||
if(mouse[1] > 10) WallBuilder[client].angles[0] += WallBuilder[client].snapAngle;
|
Editor[client].hasCollisionRotate = false;
|
||||||
else if(mouse[1] < -10) WallBuilder[client].angles[0] -= WallBuilder[client].snapAngle;
|
if(Editor[client].axis == 3) {
|
||||||
} else if(WallBuilder[client].axis == 1) {
|
if(mouse[1] > 10) Editor[client].angles[2] += Editor[client].snapAngle;
|
||||||
if(mouse[0] > 10) WallBuilder[client].angles[1] += WallBuilder[client].snapAngle;
|
else if(mouse[1] < -10) Editor[client].angles[2] -= Editor[client].snapAngle;
|
||||||
else if(mouse[0] < -10) WallBuilder[client].angles[1] -= WallBuilder[client].snapAngle;
|
|
||||||
} else {
|
} 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[1] < -10) WallBuilder[client].angles[2] -= WallBuilder[client].snapAngle;
|
else if(mouse[0] < -10) Editor[client].angles[Editor[client].axis] -= Editor[client].snapAngle;
|
||||||
|
|
||||||
}
|
}
|
||||||
cmdThrottle[client] = tick;
|
cmdThrottle[client] = tick;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if(g_inRotate[client]) {
|
||||||
|
g_inRotate[client] = false;
|
||||||
|
}
|
||||||
// Move position
|
// Move position
|
||||||
if(buttons & IN_ATTACK) WallBuilder[client].moveDistance++;
|
if(buttons & IN_ATTACK) Editor[client].moveDistance++;
|
||||||
else if(buttons & IN_ATTACK2) WallBuilder[client].moveDistance--;
|
else if(buttons & IN_ATTACK2) Editor[client].moveDistance--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear IN_FROZEN when no longer rotate
|
// 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;
|
flags = flags & ~FL_FROZEN;
|
||||||
SetEntityFlags(client, flags);
|
SetEntityFlags(client, flags);
|
||||||
}
|
}
|
||||||
|
GetEditorPosition(client, Filter_IgnorePlayerAndWall);
|
||||||
GetCursorLimited2(client, WallBuilder[client].moveDistance, WallBuilder[client].origin, Filter_IgnorePlayerAndWall, WallBuilder[client].hasCollision);
|
|
||||||
}
|
}
|
||||||
case SCALE: {
|
case SCALE: {
|
||||||
SetWeaponDelay(client, 0.5);
|
SetWeaponDelay(client, 0.5);
|
||||||
|
@ -625,74 +668,77 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
||||||
bool sizeChanged = false;
|
bool sizeChanged = false;
|
||||||
switch(buttons) {
|
switch(buttons) {
|
||||||
case IN_MOVELEFT: {
|
case IN_MOVELEFT: {
|
||||||
WallBuilder[client].size[0] -=WallBuilder[client].moveSpeed;
|
Editor[client].size[0] -=Editor[client].moveSpeed;
|
||||||
if(WallBuilder[client].size[0] <= 0.0) WallBuilder[client].size[0] = 0.0;
|
if(Editor[client].size[0] <= 0.0) Editor[client].size[0] = 0.0;
|
||||||
sizeChanged = true;
|
sizeChanged = true;
|
||||||
} case IN_MOVERIGHT: {
|
} case IN_MOVERIGHT: {
|
||||||
WallBuilder[client].size[0] += WallBuilder[client].moveSpeed;
|
Editor[client].size[0] += Editor[client].moveSpeed;
|
||||||
sizeChanged = true;
|
sizeChanged = true;
|
||||||
} case IN_FORWARD: {
|
} case IN_FORWARD: {
|
||||||
WallBuilder[client].size[1]+= WallBuilder[client].moveSpeed;
|
Editor[client].size[1]+= Editor[client].moveSpeed;
|
||||||
sizeChanged = true;
|
sizeChanged = true;
|
||||||
} case IN_BACK: {
|
} case IN_BACK: {
|
||||||
WallBuilder[client].size[1] -= WallBuilder[client].moveSpeed;
|
Editor[client].size[1] -= Editor[client].moveSpeed;
|
||||||
if(WallBuilder[client].size[1] <= 0.0) WallBuilder[client].size[1] = 0.0;
|
if(Editor[client].size[1] <= 0.0) Editor[client].size[1] = 0.0;
|
||||||
sizeChanged = true;
|
sizeChanged = true;
|
||||||
} case IN_JUMP: {
|
} case IN_JUMP: {
|
||||||
WallBuilder[client].size[2] += WallBuilder[client].moveSpeed;
|
Editor[client].size[2] += Editor[client].moveSpeed;
|
||||||
sizeChanged = true;
|
sizeChanged = true;
|
||||||
} case IN_DUCK: {
|
} case IN_DUCK: {
|
||||||
if(WallBuilder[client].size[2] <= 0.0) WallBuilder[client].size[2] = 0.0;
|
if(Editor[client].size[2] <= 0.0) Editor[client].size[2] = 0.0;
|
||||||
WallBuilder[client].size[2] -= WallBuilder[client].moveSpeed;
|
Editor[client].size[2] -= Editor[client].moveSpeed;
|
||||||
sizeChanged = true;
|
sizeChanged = true;
|
||||||
}
|
}
|
||||||
case IN_USE: WallBuilder[client].CycleSpeed(client, tick);
|
case IN_USE: Editor[client].CycleSpeed(client, tick);
|
||||||
}
|
}
|
||||||
if(sizeChanged) {
|
if(sizeChanged) {
|
||||||
WallBuilder[client].CalculateMins();
|
Editor[client].CalculateMins();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case COLOR: {
|
case COLOR: {
|
||||||
SetWeaponDelay(client, 0.5);
|
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) {
|
if(buttons & IN_USE) {
|
||||||
WallBuilder[client].CycleColorComponent(client, tick);
|
Editor[client].CycleColorComponent(client, tick);
|
||||||
} else if(buttons & IN_ATTACK) {
|
} else if(buttons & IN_ATTACK) {
|
||||||
WallBuilder[client].color[WallBuilder[client].colorIndex]--;
|
Editor[client].color[Editor[client].colorIndex]--;
|
||||||
if(WallBuilder[client].color[WallBuilder[client].colorIndex] < 0) {
|
if(Editor[client].color[Editor[client].colorIndex] < 0) {
|
||||||
WallBuilder[client].color[WallBuilder[client].colorIndex] = 0;
|
Editor[client].color[Editor[client].colorIndex] = 0;
|
||||||
}
|
}
|
||||||
WallBuilder[client].UpdateEntity();
|
Editor[client].UpdateEntity();
|
||||||
allowMove = false;
|
allowMove = false;
|
||||||
} else if(buttons & IN_ATTACK2) {
|
} else if(buttons & IN_ATTACK2) {
|
||||||
WallBuilder[client].color[WallBuilder[client].colorIndex]++;
|
Editor[client].color[Editor[client].colorIndex]++;
|
||||||
if(WallBuilder[client].color[WallBuilder[client].colorIndex] > 255) {
|
if(Editor[client].color[Editor[client].colorIndex] > 255) {
|
||||||
WallBuilder[client].color[WallBuilder[client].colorIndex] = 255;
|
Editor[client].color[Editor[client].colorIndex] = 255;
|
||||||
}
|
}
|
||||||
WallBuilder[client].UpdateEntity();
|
Editor[client].UpdateEntity();
|
||||||
allowMove = false;
|
allowMove = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(buttons & IN_RELOAD)
|
if(buttons & IN_RELOAD)
|
||||||
WallBuilder[client].CycleMode(client, tick); // R: Cycle forward
|
Editor[client].CycleMode(client, tick); // R: Cycle forward
|
||||||
else if(WallBuilder[client].flags & Edit_Preview && tick - cmdThrottle[client] >= 0.25 && buttons & IN_ZOOM) {
|
else if(Editor[client].flags & Edit_Preview && tick - cmdThrottle[client] >= 0.25 && buttons & IN_ZOOM) {
|
||||||
|
buttons &= ~IN_ZOOM;
|
||||||
if(buttons & IN_SPEED) {
|
if(buttons & IN_SPEED) {
|
||||||
int entity;
|
int entity;
|
||||||
WallBuilder[client].Create(entity);
|
Editor[client].Create(entity);
|
||||||
int index = g_spawnedItems.Push(EntIndexToEntRef(entity));
|
AddSpawnedItem(entity, client);
|
||||||
g_spawnedItems.Set(index, GetClientUserId(client), 1);
|
char model[128];
|
||||||
|
GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||||
|
AddRecent(model, Editor[client].data);
|
||||||
} else if(buttons & IN_DUCK) {
|
} else if(buttons & IN_DUCK) {
|
||||||
WallBuilder[client].CycleBuildType(client);
|
Editor[client].CycleBuildType(client);
|
||||||
} else {
|
} else {
|
||||||
WallBuilder[client].Cancel();
|
Editor[client].Cancel();
|
||||||
CPrintToChat(client, "\x04[Editor]\x01 Cancelled.");
|
CPrintToChat(client, "\x04[Editor]\x01 Cancelled.");
|
||||||
}
|
}
|
||||||
cmdThrottle[client] = tick;
|
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;
|
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) {
|
public void OnClientDisconnect(int client) {
|
||||||
tempGod[client] = false;
|
tempGod[client] = false;
|
||||||
WallBuilder[client].Reset();
|
Editor[client].Reset();
|
||||||
g_isSearchActive[client] = false;
|
g_PropData[client].Reset();
|
||||||
g_lastCategoryIndex[client] = 0;
|
|
||||||
g_lastItemIndex[client] = 0;
|
|
||||||
g_lastShowedHint[client] = 0;
|
|
||||||
hatData[client].yeetGroundTimer = null;
|
hatData[client].yeetGroundTimer = null;
|
||||||
|
if(g_pendingSaveClient == client) {
|
||||||
|
g_pendingSaveClient = 0;
|
||||||
|
ClearSavePreview();
|
||||||
|
}
|
||||||
ClearHat(client, true);
|
ClearHat(client, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -797,6 +844,7 @@ public void OnMapEnd() {
|
||||||
ClearHats();
|
ClearHats();
|
||||||
UnloadCategories();
|
UnloadCategories();
|
||||||
UnloadSave();
|
UnloadSave();
|
||||||
|
SaveRecents();
|
||||||
}
|
}
|
||||||
public void OnPluginEnd() {
|
public void OnPluginEnd() {
|
||||||
ClearHats();
|
ClearHats();
|
||||||
|
@ -807,10 +855,10 @@ public void OnPluginEnd() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(g_spawnedItems != null) {
|
if(g_spawnedItems != null) {
|
||||||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
// for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||||
int ref = g_spawnedItems.Get(i);
|
// int ref = g_spawnedItems.Get(i);
|
||||||
RemoveEntity(ref);
|
// RemoveEntity(ref);
|
||||||
}
|
// }
|
||||||
delete g_spawnedItems;
|
delete g_spawnedItems;
|
||||||
}
|
}
|
||||||
TriggerInput("prop_preview", "Kill");
|
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) {
|
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;
|
return float(RoundFloat(value / degree)) * degree;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a position from where the cursor is upto distance away (basically <= distance, going against walls)
|
stock bool GetEditorPosition(int client, TraceEntityFilter filter) {
|
||||||
stock bool GetCursorLimited2(int client, float distance, float endPos[3], TraceEntityFilter filter, bool doCollide = true) {
|
|
||||||
if (client > 0 && client <= MaxClients && IsClientInGame(client)) {
|
if (client > 0 && client <= MaxClients && IsClientInGame(client)) {
|
||||||
float clientEye[3], clientAngle[3], direction[3];
|
float clientEye[3], clientAngle[3], direction[3];
|
||||||
GetClientEyePosition(client, clientEye);
|
GetClientEyePosition(client, clientEye);
|
||||||
GetClientEyeAngles(client, clientAngle);
|
GetClientEyeAngles(client, clientAngle);
|
||||||
|
|
||||||
GetAngleVectors(clientAngle, direction, NULL_VECTOR, NULL_VECTOR);
|
GetAngleVectors(clientAngle, direction, NULL_VECTOR, NULL_VECTOR);
|
||||||
ScaleVector(direction, distance);
|
ScaleVector(direction, Editor[client].moveDistance);
|
||||||
AddVectors(clientEye, direction, endPos);
|
AddVectors(clientEye, direction, Editor[client].origin);
|
||||||
|
|
||||||
if(doCollide) {
|
if(Editor[client].hasCollision) {
|
||||||
TR_TraceRayFilter(clientEye, endPos, MASK_OPAQUE, RayType_EndPoint, filter, client);
|
TR_TraceRayFilter(clientEye, Editor[client].origin, MASK_OPAQUE, RayType_EndPoint, filter, client);
|
||||||
if (TR_DidHit(INVALID_HANDLE)) {
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4417
scripting/l4d2_spawn_props.sp
Normal file
4417
scripting/l4d2_spawn_props.sp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -263,6 +263,7 @@ int AddMountedGun(int entity, MountedGun type) {
|
||||||
DispatchKeyValue(poseCtrl, "targetname", buffer);
|
DispatchKeyValue(poseCtrl, "targetname", buffer);
|
||||||
DispatchKeyValue(poseCtrl, "PoseParameterName", "MiniGun_Horizontal");
|
DispatchKeyValue(poseCtrl, "PoseParameterName", "MiniGun_Horizontal");
|
||||||
DispatchKeyValue(poseCtrl, "CycleFrequency", "0");
|
DispatchKeyValue(poseCtrl, "CycleFrequency", "0");
|
||||||
|
DispatchKeyValue(poseCtrl, "FModRate", "0");
|
||||||
DispatchSpawn(poseCtrl);
|
DispatchSpawn(poseCtrl);
|
||||||
SetParent(poseCtrl, entity);
|
SetParent(poseCtrl, entity);
|
||||||
MTurret[MTurretCount].poseController = EntIndexToEntRef(poseCtrl);
|
MTurret[MTurretCount].poseController = EntIndexToEntRef(poseCtrl);
|
||||||
|
@ -669,9 +670,14 @@ public Action Timer_Think(Handle h) {
|
||||||
targetPos[2] += 40.0; // hit infected better
|
targetPos[2] += 40.0; // hit infected better
|
||||||
GetAngles(pos, targetPos, angles);
|
GetAngles(pos, targetPos, angles);
|
||||||
float angle = 0.5 + (angles[1] - turretAngles[1]) / FLOAT_PI;
|
float angle = 0.5 + (angles[1] - turretAngles[1]) / FLOAT_PI;
|
||||||
SetPoseControllerParameter(MTurret[i].poseController, "MiniGun_Vertical", -90.0, 90.0, angle);
|
SetVariantString("Minigun_Horizontal");
|
||||||
angle = 0.5 + (angles[0] - turretAngles[0]) / FLOAT_PI;
|
AcceptEntityInput(MTurret[i].poseController, "SetPoseParameterName");
|
||||||
SetPoseControllerParameter(MTurret[i].poseController, "MiniGun_Horizontal", -90.0, 90.0, angle);
|
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, 0, -90.0, 90.0, angles[0]);
|
||||||
// SetPoseParameter(MTurret[i].entity, 1, -90.0, 90.0, angles[1]);
|
// SetPoseParameter(MTurret[i].entity, 1, -90.0, 90.0, angles[1]);
|
||||||
TR_TraceRay(pos, targetPos, 0, RayType_EndPoint);
|
TR_TraceRay(pos, targetPos, 0, RayType_EndPoint);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue