mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-05 15:53:20 +00:00
Updates
This commit is contained in:
parent
fd2367f41f
commit
79d37bdd34
45 changed files with 5587 additions and 3877 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -36,7 +36,7 @@ int g_BeamSprite;
|
|||
int g_HaloSprite;
|
||||
int g_iLaserIndex;
|
||||
|
||||
#define MAX_FORBIDDEN_CLASSNAMES 9
|
||||
#define MAX_FORBIDDEN_CLASSNAMES 10
|
||||
static char FORBIDDEN_CLASSNAMES[MAX_FORBIDDEN_CLASSNAMES][] = {
|
||||
// "env_physics_blocker",
|
||||
// "env_player_blocker",
|
||||
|
@ -49,7 +49,8 @@ static char FORBIDDEN_CLASSNAMES[MAX_FORBIDDEN_CLASSNAMES][] = {
|
|||
"func_tracktrain",
|
||||
// "infected",
|
||||
"func_lod",
|
||||
"prop_ragdoll"
|
||||
"prop_ragdoll",
|
||||
"move_rope"
|
||||
};
|
||||
|
||||
#define MAX_FORBIDDEN_MODELS 2
|
||||
|
@ -65,9 +66,11 @@ static char HIGHLIGHTED_CLASSNAMES[MAX_HIGHLIGHTED_CLASSNAMES][] = {
|
|||
"func_brush"
|
||||
}
|
||||
|
||||
ConVar g_cvarEnabled;
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
g_cvarEnabled = CreateConVar("sm_grabent_allow", "1", "Is grabent allowed", FCVAR_NONE, true, 0.0, true, 1.0);
|
||||
RegAdminCmd("sm_grabent_freeze", Cmd_ReleaseFreeze, ADMFLAG_CHEATS, "<0/1> - Toggle entity freeze/unfreeze on release.");
|
||||
RegAdminCmd("sm_grab", Cmd_Grab, ADMFLAG_CHEATS, "Toggle Grab the entity in your crosshair.");
|
||||
RegAdminCmd("+grabent", Cmd_Grab, ADMFLAG_CHEATS, "Grab the entity in your crosshair.");
|
||||
|
@ -131,11 +134,13 @@ public Action Cmd_ReleaseFreeze(client, args)
|
|||
//============================================================================
|
||||
// GRAB ENTITY COMMAND //
|
||||
//============================================================================
|
||||
public Action Cmd_Grab(client, args) {
|
||||
if (client < 1 || client > MaxClients || !IsClientInGame(client))
|
||||
Action Cmd_Grab(int client, int args) {
|
||||
if(!g_cvarEnabled.BoolValue) {
|
||||
ReplyToCommand(client, "[SM] Grabent is disabled");
|
||||
return Plugin_Handled;
|
||||
|
||||
if (g_pGrabbedEnt[client] > 0 && IsValidEntity(g_pGrabbedEnt[client])) {
|
||||
} else if (client < 1 || client > MaxClients || !IsClientInGame(client)) {
|
||||
return Plugin_Handled;
|
||||
} else if (g_pGrabbedEnt[client] > 0 && IsValidEntity(g_pGrabbedEnt[client])) {
|
||||
Cmd_Release(client, 0);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
@ -572,6 +577,7 @@ bool Filter_IgnoreForbidden(int entity, int mask, int data) {
|
|||
}
|
||||
|
||||
bool CheckBlacklist(int entity) {
|
||||
if(entity == 0) return false;
|
||||
static char buffer[64];
|
||||
GetEntityClassname(entity, buffer, sizeof(buffer));
|
||||
for(int i = 0; i < MAX_FORBIDDEN_CLASSNAMES; i++) {
|
||||
|
@ -591,5 +597,6 @@ bool CheckBlacklist(int entity) {
|
|||
if(StrEqual(buffer, "l4d2_randomizer")) {
|
||||
return false;
|
||||
}
|
||||
GetEntityClassname(entity, buffer, sizeof(buffer));
|
||||
return true;
|
||||
}
|
|
@ -461,6 +461,10 @@ Action Command_SetClientModel(int client, int args) {
|
|||
|
||||
void SetCharacter(int target, int survivorIndex, L4DModelId modelIndex, bool keepModel) {
|
||||
SetEntProp(target, Prop_Send, "m_survivorCharacter", survivorIndex);
|
||||
if(!PrecacheModel(MODELS[view_as<int>(modelIndex)])) {
|
||||
LogError("SetCharacter: INVALID MODEL: %s", MODELS[view_as<int>(modelIndex)]);
|
||||
return;
|
||||
}
|
||||
SetEntityModel(target, MODELS[view_as<int>(modelIndex)]);
|
||||
if (IsFakeClient(target)) {
|
||||
char name[32];
|
||||
|
@ -629,6 +633,9 @@ public void OnMapStart() {
|
|||
PrecacheSound(PRECACHE_SOUNDS[i]);
|
||||
}
|
||||
#endif
|
||||
for(int i = 0; i < 8; i++) {
|
||||
PrecacheModel(MODELS[i]);
|
||||
}
|
||||
|
||||
HookEntityOutput("info_changelevel", "OnStartTouch", EntityOutput_OnStartTouchSaferoom);
|
||||
HookEntityOutput("trigger_changelevel", "OnStartTouch", EntityOutput_OnStartTouchSaferoom);
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
#include <multicolors>
|
||||
#include <jutils>
|
||||
#include <socket>
|
||||
#include <SteamWorks>
|
||||
#undef REQUIRE_PLUGIN
|
||||
#tryinclude <SteamWorks>
|
||||
|
||||
#pragma newdecls required
|
||||
|
||||
|
@ -85,7 +86,7 @@ public void OnPluginStart() {
|
|||
g_socket.SetOption(SocketSendBuffer, BUFFER_SIZE);
|
||||
|
||||
uptime = GetTime();
|
||||
cvar_debug = CreateConVar("sm_adminpanel_debug", "1", "Turn on debug mode", FCVAR_DONTRECORD, true, 0.0, true, 1.0);
|
||||
cvar_debug = CreateConVar("sm_adminpanel_debug", "0", "Turn on debug mode", FCVAR_DONTRECORD, true, 0.0, true, 1.0);
|
||||
|
||||
cvar_authToken = CreateConVar("sm_adminpanel_authtoken", "", "The token for authentication", FCVAR_PROTECTED);
|
||||
cvar_authToken.AddChangeHook(OnCvarChanged);
|
||||
|
@ -172,10 +173,7 @@ void OnSocketError(Socket socket, int errorType, int errorNumber, int any) {
|
|||
}
|
||||
|
||||
void SendFullSync() {
|
||||
PrintToServer("SendFullSync");
|
||||
if(StartPayload(true)) {
|
||||
PrintToServer("SendFullSync : Started");
|
||||
|
||||
AddGameRecord();
|
||||
int stage = L4D2_GetCurrentFinaleStage();
|
||||
if(stage != 0)
|
||||
|
@ -254,15 +252,19 @@ void OnSocketReceive(Socket socket, const char[] receiveData, int dataSize, int
|
|||
}
|
||||
|
||||
void ProcessCommand(int id, const char[] command, const char[] cmdNamespace = "") {
|
||||
char output[128];
|
||||
char output[1024];
|
||||
if(!StartPayload(true)) return;
|
||||
if(cmdNamespace[0] == '\0' || StrEqual(cmdNamespace, "default")) {
|
||||
SplitString(command, " ", output, sizeof(output));
|
||||
// If command has no spaces, we need to manually copy the command to the split part
|
||||
if(SplitString(command, " ", output, sizeof(output)) == -1) {
|
||||
strcopy(output, sizeof(output), command);
|
||||
}
|
||||
if(CommandExists(output)) {
|
||||
ServerCommandEx(output, sizeof(output), "%s", command);
|
||||
AddCommandResponseRecord(id, Result_Boolean, 1, output);
|
||||
} else {
|
||||
AddCommandResponseRecord(id, Result_Error, -1, "Command does not exist");
|
||||
Format(output, sizeof(output), "Command \"%s\" does not exist", output);
|
||||
AddCommandResponseRecord(id, Result_Error, -1, output);
|
||||
}
|
||||
} else if(StrEqual(cmdNamespace, "builtin")) {
|
||||
CommandResultType type;
|
||||
|
|
|
@ -50,7 +50,9 @@ stock void EntFire(const char[] name, const char[] input) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void CreateCoinEntity(float pos[3]) {
|
||||
// int ent = CreateProp("prop_dynamic", "")
|
||||
}
|
||||
|
||||
void SetupEntities(bool blockers = true, bool props = true, bool portals = true) {
|
||||
#if defined DEBUG_BLOCKERS
|
||||
|
|
|
@ -125,6 +125,12 @@ methodmap GuessWhoGame < BaseGame {
|
|||
}
|
||||
}
|
||||
|
||||
property int TargetCoinCount {
|
||||
public get() {
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void Start() {
|
||||
|
||||
}
|
||||
|
@ -301,6 +307,14 @@ methodmap GuessWhoGame < BaseGame {
|
|||
SDKUnhook(client, SDKHook_OnTakeDamageAlive, OnTakeDamageAlive);
|
||||
SDKUnhook(client, SDKHook_WeaponEquip, OnWeaponEquip);
|
||||
}
|
||||
|
||||
public void PopulateCoins() {
|
||||
float pos[3];
|
||||
for(int i = 0; i < this.TargetCoinCount; i++) {
|
||||
movePoints.GetRandomPoint(pos);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stock bool ArePlayersJoining() {
|
||||
|
|
|
@ -13,13 +13,18 @@ Action Timer_RecordPoints(Handle h, int i) {
|
|||
vecLastLocation[i] = meta.pos;
|
||||
}
|
||||
}
|
||||
Game.MapTime++;
|
||||
PrintHintText(i, "Points: %d / %d", movePoints.Length, MAX_VALID_LOCATIONS);
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
|
||||
bool firstCheckDone = false;
|
||||
Action Timer_WaitForPlayers(Handle h) {
|
||||
if(!isEnabled) return Plugin_Stop;
|
||||
if(!isEnabled) {
|
||||
waitTimer = null;
|
||||
return Plugin_Stop;
|
||||
}
|
||||
if(!ArePlayersJoining()) {
|
||||
Game.Debug("No players pending, ready to go");
|
||||
if(!firstCheckDone) {
|
||||
|
@ -28,6 +33,7 @@ Action Timer_WaitForPlayers(Handle h) {
|
|||
} else {
|
||||
firstCheckDone = false;
|
||||
InitGamemode();
|
||||
waitTimer = null;
|
||||
return Plugin_Stop;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
native bool SpawnSchematic(const char name[32], const float pos[3], const float angles[3] = NULL_VECTOR);
|
|
@ -1,7 +1,6 @@
|
|||
int BUILDER_COLOR[4] = { 0, 255, 0, 235 };
|
||||
int GLOW_BLUE[4] = { 3, 148, 252 };
|
||||
int GLOW_RED_ALPHA[4] = { 255, 0, 0, 235 };
|
||||
int GLOW_RED[3] = { 255, 0, 0};
|
||||
int GLOW_WHITE[4] = { 255, 255, 255, 255 };
|
||||
int GLOW_GREEN[4] = { 3, 252, 53 };
|
||||
float ORIGIN_SIZE[3] = { 2.0, 2.0, 2.0 };
|
||||
|
@ -27,26 +26,21 @@ char MODE_NAME[5][] = {
|
|||
"Freelook"
|
||||
}
|
||||
|
||||
enum editFlag {
|
||||
enum {
|
||||
Edit_None,
|
||||
Edit_Copy = 1,
|
||||
Edit_Preview = 2,
|
||||
Edit_WallCreator = 4
|
||||
Edit_WallCreator = 4,
|
||||
Edit_Manager = 8
|
||||
}
|
||||
|
||||
enum buildType {
|
||||
Build_Solid,
|
||||
Build_Physics,
|
||||
Build_NonSolid,
|
||||
// TODO: Build_Weapon (spawn as weapon?)
|
||||
}
|
||||
|
||||
enum CompleteType {
|
||||
Complete_WallSuccess,
|
||||
Complete_WallError,
|
||||
Complete_PropSpawned,
|
||||
Complete_PropError,
|
||||
Complete_EditSuccess
|
||||
}
|
||||
|
||||
enum StackerDirection {
|
||||
Stack_Off,
|
||||
|
@ -88,6 +82,7 @@ enum struct EditorData {
|
|||
int colorIndex;
|
||||
int axis;
|
||||
int snapAngle;
|
||||
float rotateSpeed;
|
||||
int moveSpeed;
|
||||
float moveDistance;
|
||||
int entity;
|
||||
|
@ -97,11 +92,14 @@ enum struct EditorData {
|
|||
|
||||
editMode mode;
|
||||
buildType buildType;
|
||||
editFlag flags;
|
||||
int flags;
|
||||
|
||||
PrivateForward callback;
|
||||
bool isEditCallback;
|
||||
|
||||
void Reset(bool initial = false) {
|
||||
// Clear preview entity
|
||||
if(this.entity != INVALID_ENT_REFERENCE && this.flags & Edit_Preview && IsValidEntity(this.entity)) {
|
||||
if(this.entity != INVALID_ENT_REFERENCE && (this.flags & Edit_Preview) && IsValidEntity(this.entity)) {
|
||||
RemoveEntity(this.entity);
|
||||
}
|
||||
this.stackerDirection = Stack_Off;
|
||||
|
@ -111,12 +109,13 @@ enum struct EditorData {
|
|||
this.size[0] = this.size[1] = this.size[2] = 5.0;
|
||||
this.angles[0] = this.angles[1] = this.angles[2] = 0.0;
|
||||
this.colorIndex = 0;
|
||||
this.axis = 1;
|
||||
this.axis = 0;
|
||||
this.moveDistance = 200.0;
|
||||
this.flags = Edit_None;
|
||||
this.classname[0] = '\0';
|
||||
this.CalculateMins();
|
||||
this.SetMode(INACTIVE);
|
||||
this.rotateSpeed = 0.1;
|
||||
// Settings that don't get reset on new spawns:
|
||||
if(initial) {
|
||||
this.color[0] = this.color[1] = this.color[2] = this.color[3] = 255;
|
||||
|
@ -138,6 +137,12 @@ enum struct EditorData {
|
|||
if(this.flags & Edit_WallCreator || this.entity == INVALID_ENT_REFERENCE) {
|
||||
Effect_DrawBeamBoxRotatableToAll(this.origin, this.mins, this.size, this.angles, g_iLaserIndex, 0, 0, 30, lifetime, 0.4, 0.4, 0, amplitude, color, 0);
|
||||
} else {
|
||||
if(this.snapAngle != 1) {
|
||||
this.angles[0] = RoundToNearestInterval(this.angles[0], this.snapAngle);
|
||||
this.angles[1] = RoundToNearestInterval(this.angles[1], this.snapAngle);
|
||||
this.angles[2] = RoundToNearestInterval(this.angles[2], this.snapAngle);
|
||||
|
||||
}
|
||||
TeleportEntity(this.entity, this.origin, this.angles, NULL_VECTOR);
|
||||
}
|
||||
Effect_DrawAxisOfRotationToAll(this.origin, this.angles, ORIGIN_SIZE, g_iLaserIndex, 0, 0, 30, 0.2, 0.1, 0.1, 0, 0.0, 0);
|
||||
|
@ -147,9 +152,6 @@ enum struct EditorData {
|
|||
void UpdateEntity() {
|
||||
int alpha = this.color[3];
|
||||
// Keep previews transparent
|
||||
if(this.flags & Edit_Preview) {
|
||||
alpha = 200;
|
||||
}
|
||||
SetEntityRenderColor(this.entity, this.color[0], this.color[1], this.color[2], alpha);
|
||||
}
|
||||
|
||||
|
@ -178,6 +180,10 @@ enum struct EditorData {
|
|||
void SetName(const char[] name) {
|
||||
strcopy(this.name, sizeof(this.name), name);
|
||||
}
|
||||
void SetCallback(PrivateForward callback, bool isEditCallback) {
|
||||
this.callback = callback;
|
||||
this.isEditCallback = isEditCallback;
|
||||
}
|
||||
|
||||
void CycleMode() {
|
||||
// Remove frozen state when cycling
|
||||
|
@ -210,43 +216,43 @@ enum struct EditorData {
|
|||
PrintToChat(this.client, "\x04[Editor]\x01 Mode: \x05%s\x01 (Press \x04RELOAD\x01 to change)", MODE_NAME[this.mode]);
|
||||
}
|
||||
|
||||
void CycleStacker(float tick) {
|
||||
if(tick - cmdThrottle[this.client] <= 0.10) return;
|
||||
void CycleStacker() {
|
||||
int newDirection = view_as<int>(this.stackerDirection) + 1;
|
||||
if(newDirection == view_as<int>(Stack_Down)) newDirection = 0;
|
||||
this.stackerDirection = view_as<StackerDirection>(newDirection);
|
||||
|
||||
PrintToChat(this.client, "\x04[Editor]\x01 Stacker: %s\x01", STACK_DIRECTION_NAME[this.stackerDirection]);
|
||||
cmdThrottle[this.client] = tick;
|
||||
}
|
||||
|
||||
void ToggleCollision(float tick) {
|
||||
if(tick - cmdThrottle[this.client] <= 0.25) return;
|
||||
void ToggleCollision() {
|
||||
this.hasCollision = !this.hasCollision
|
||||
PrintToChat(this.client, "\x04[Editor]\x01 Collision: %s", ON_OFF_STRING[view_as<int>(this.hasCollision)]);
|
||||
cmdThrottle[this.client] = tick;
|
||||
}
|
||||
|
||||
void ToggleCollisionRotate(float tick) {
|
||||
if(tick - cmdThrottle[this.client] <= 0.20) return;
|
||||
void ToggleCollisionRotate() {
|
||||
this.hasCollisionRotate = !this.hasCollisionRotate
|
||||
PrintToChat(this.client, "\x04[Editor]\x01 Rotate with Collision: %s", ON_OFF_STRING[view_as<int>(this.hasCollisionRotate)]);
|
||||
cmdThrottle[this.client] = tick;
|
||||
}
|
||||
|
||||
void CycleAxis(float tick) {
|
||||
if(tick - cmdThrottle[this.client] <= 0.1) return;
|
||||
void CycleAxis() {
|
||||
// if(tick - cmdThrottle[this.client] <= 0.1) return;
|
||||
if(this.axis == 0) {
|
||||
this.axis = 1;
|
||||
PrintToChat(this.client, "\x04[Editor]\x01 Rotate Axis: \x05HEADING (Y)\x01");
|
||||
} else if(this.axis == 1) {
|
||||
this.axis = 2;
|
||||
PrintToChat(this.client, "\x04[Editor]\x01 Rotate Axis: \x05PITCH (X)\x01");
|
||||
PrintToChat(this.client, "\x04[Editor]\x01 Rotate Axis: \x05ROLL (Z)\x01");
|
||||
} else {
|
||||
this.axis = 0;
|
||||
PrintToChat(this.client, "\x04[Editor]\x01 Rotate Axis: \x05ROLL (Z)\x01");
|
||||
PrintToChat(this.client, "\x04[Editor]\x01 Rotate Axis: \x05PITCH AND HEADING (X, Y)\x01");
|
||||
}
|
||||
// cmdThrottle[this.client] = tick;
|
||||
}
|
||||
|
||||
void IncrementAxis(int axis, int mouse) {
|
||||
if(this.snapAngle == 1) {
|
||||
this.angles[axis] += mouse * this.rotateSpeed;
|
||||
} else {
|
||||
if(mouse > 0) this.angles[axis] += this.snapAngle;
|
||||
else if(mouse < 0) this.angles[axis] -= this.snapAngle;
|
||||
}
|
||||
cmdThrottle[this.client] = tick;
|
||||
}
|
||||
|
||||
void CycleSnapAngle(float tick) {
|
||||
|
@ -328,18 +334,38 @@ enum struct EditorData {
|
|||
|
||||
// Complete the edit, wall creation, or spawning
|
||||
CompleteType Done(int& entity) {
|
||||
CompleteType type;
|
||||
if(this.flags & Edit_WallCreator) {
|
||||
return this._FinishWall(entity) ? Complete_WallSuccess : Complete_WallError;
|
||||
type = this._FinishWall(entity) ? Complete_WallSuccess : Complete_WallError;
|
||||
} else if(this.flags & Edit_Preview) {
|
||||
return this._FinishPreview(entity) ? Complete_PropSpawned : Complete_PropError;
|
||||
type = this._FinishPreview(entity) ? Complete_PropSpawned : Complete_PropError;
|
||||
} else {
|
||||
// Is edit, do nothing, just reset
|
||||
PrintHintText(this.client, "Edit Complete");
|
||||
this.Reset();
|
||||
entity = 0;
|
||||
|
||||
return Complete_EditSuccess;
|
||||
type = Complete_EditSuccess;
|
||||
}
|
||||
if(this.callback) {
|
||||
Call_StartForward(this.callback);
|
||||
Call_PushCell(this.client);
|
||||
Call_PushCell(entity);
|
||||
Call_PushCell(type);
|
||||
bool result;
|
||||
Call_Finish(result);
|
||||
// Cancel menu:
|
||||
if(this.isEditCallback) delete this.callback;
|
||||
if(this.isEditCallback || !result) {
|
||||
// No native way to close a menu, so open a dummy menu and close it:
|
||||
// Handler doesn't matter, no options are added
|
||||
Menu menu = new Menu(Spawn_RootHandler);
|
||||
menu.Display(this.client, 1);
|
||||
} else {
|
||||
delete this.callback;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
bool _FinishWall(int& id) {
|
||||
|
@ -569,7 +595,7 @@ enum struct EditorData {
|
|||
DispatchKeyValue(entity, "targetname", "prop_preview");
|
||||
DispatchKeyValue(entity, "solid", "0");
|
||||
DispatchKeyValue(entity, "rendercolor", "255 128 255");
|
||||
DispatchKeyValue(entity, "renderamt", "200");
|
||||
DispatchKeyValue(entity, "renderamt", "255");
|
||||
DispatchKeyValue(entity, "rendermode", "1");
|
||||
TeleportEntity(entity, this.origin, NULL_VECTOR, NULL_VECTOR);
|
||||
if(!DispatchSpawn(entity)) {
|
||||
|
@ -583,8 +609,11 @@ enum struct EditorData {
|
|||
return IsValidEntity(entity);
|
||||
}
|
||||
|
||||
// Adds an existing entity to the editor, to move it.
|
||||
// asWallCopy: to instead copy the wall's size and position (walls only)
|
||||
/**
|
||||
* Adds an existing entity to the editor, to move it.
|
||||
* asWallCopy: to instead copy the wall's size and position (walls only)
|
||||
* @deprecated
|
||||
*/
|
||||
void Import(int entity, bool asWallCopy = false, editMode mode = SCALE) {
|
||||
this.Reset();
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin);
|
||||
|
@ -599,6 +628,22 @@ enum struct EditorData {
|
|||
this.SetMode(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports an entity
|
||||
*/
|
||||
void ImportEntity(int entity, int flags = 0, editMode mode = SCALE) {
|
||||
this.Reset();
|
||||
this.flags = flags;
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin);
|
||||
GetEntPropVector(entity, Prop_Send, "m_angRotation", this.angles);
|
||||
this.prevOrigin = this.origin;
|
||||
this.prevAngles = this.angles;
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecMins", this.mins);
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", this.size);
|
||||
this.entity = entity;
|
||||
this.SetMode(mode);
|
||||
}
|
||||
|
||||
// Cancels the current placement. If the edit is a copy/preview, the entity is also deleted
|
||||
// If entity is not a wall, it will be returned
|
||||
void Cancel() {
|
||||
|
@ -611,9 +656,22 @@ enum struct EditorData {
|
|||
}
|
||||
this.SetMode(INACTIVE);
|
||||
PrintHintText(this.client, "Cancelled");
|
||||
if(this.callback) {
|
||||
delete this.callback;
|
||||
}
|
||||
// CPrintToChat(this.client, "\x04[Editor]\x01 Cancelled.");
|
||||
}
|
||||
}
|
||||
|
||||
void SendEditorMessage(int client, const char[] format, any ...) {
|
||||
char message[256];
|
||||
VFormat(message, sizeof(message), format, 3);
|
||||
CPrintToChat(client, "\x04`[Editor]\x01 %s", message);
|
||||
}
|
||||
|
||||
stock float RoundToNearestInterval(float value, int interval) {
|
||||
return float(RoundFloat(value / float(interval)) * interval);
|
||||
}
|
||||
EditorData Editor[MAXPLAYERS+1];
|
||||
|
||||
Action OnWallClicked(int entity, int activator, int caller, UseType type, float value) {
|
||||
|
|
|
@ -43,7 +43,7 @@ int lastHatRequestTime[MAXPLAYERS+1];
|
|||
HatInstance hatData[MAXPLAYERS+1];
|
||||
StringMap g_HatPresets;
|
||||
|
||||
#define MAX_FORBIDDEN_CLASSNAMES 14
|
||||
#define MAX_FORBIDDEN_CLASSNAMES 15
|
||||
char FORBIDDEN_CLASSNAMES[MAX_FORBIDDEN_CLASSNAMES][] = {
|
||||
"prop_door_rotating_checkpoint",
|
||||
"env_physics_blocker",
|
||||
|
@ -59,7 +59,8 @@ char FORBIDDEN_CLASSNAMES[MAX_FORBIDDEN_CLASSNAMES][] = {
|
|||
// "infected",
|
||||
"func_lod",
|
||||
"func_door",
|
||||
"prop_ragdoll"
|
||||
"prop_ragdoll",
|
||||
"move_rope"
|
||||
};
|
||||
|
||||
#define MAX_FORBIDDEN_MODELS 2
|
||||
|
@ -73,7 +74,7 @@ char FORBIDDEN_MODELS[MAX_FORBIDDEN_MODELS][] = {
|
|||
// Classnames that should automatically trigger reverse infected
|
||||
static char REVERSE_CLASSNAMES[MAX_REVERSE_CLASSNAMES][] = {
|
||||
"infected",
|
||||
"func_movelinear"
|
||||
"func_movelinear",
|
||||
};
|
||||
|
||||
Action Command_DoAHat(int client, int args) {
|
||||
|
|
122
scripting/include/hats/natives.sp
Normal file
122
scripting/include/hats/natives.sp
Normal file
|
@ -0,0 +1,122 @@
|
|||
|
||||
int Native_StartEdit(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
int entity = GetNativeCell(2);
|
||||
Editor[client].Import(entity, false);
|
||||
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
|
||||
fwd.AddFunction(INVALID_HANDLE, GetNativeFunction(3));
|
||||
Editor[client].SetCallback(fwd, true);
|
||||
return 0;
|
||||
}
|
||||
int Native_StartSpawner(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
g_PropData[client].Selector.Cancel();
|
||||
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
|
||||
fwd.AddFunction(INVALID_HANDLE, GetNativeFunction(2));
|
||||
Editor[client].SetCallback(fwd, false);
|
||||
ShowCategoryList(client, ROOT_CATEGORY);
|
||||
return 0;
|
||||
}
|
||||
int Native_CancelEdit(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
Editor[client].Cancel();
|
||||
return 0;
|
||||
}
|
||||
int Native_IsEditorActive(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
Editor[client].IsActive();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Native_StartSelector(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
int color[3] = { 0, 255, 0 };
|
||||
PrivateForward fwd = new PrivateForward(ET_Single, Param_Cell, Param_Cell);
|
||||
fwd.AddFunction(plugin, GetNativeFunction(2));
|
||||
GetNativeArray(3, color, 3);
|
||||
int limit = GetNativeCell(4);
|
||||
g_PropData[client].Selector.Start(color, 0, limit);
|
||||
g_PropData[client].Selector.SetOnEnd(fwd);
|
||||
return 0;
|
||||
}
|
||||
int Native_CancelSelector(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
g_PropData[client].Selector.Cancel();
|
||||
return 0;
|
||||
}
|
||||
int Native_IsSelectorActive(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
g_PropData[client].Selector.IsActive();
|
||||
return 0;
|
||||
}
|
||||
int Native_Selector_Start(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
int color[3] = { 0, 255, 0 };
|
||||
GetNativeArray(2, color, 3);
|
||||
int flags = GetNativeCell(3);
|
||||
int limit = GetNativeCell(4);
|
||||
g_PropData[client].Selector.Start(color, flags, limit);
|
||||
return 0;
|
||||
}
|
||||
int Native_Selector_GetCount(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
if(!g_PropData[client].Selector.IsActive()) {
|
||||
return -1;
|
||||
} else {
|
||||
return g_PropData[client].Selector.list.Length;
|
||||
}
|
||||
}
|
||||
int Native_Selector_GetActive(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
return g_PropData[client].Selector.IsActive();
|
||||
}
|
||||
int Native_Selector_SetOnEnd(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell);
|
||||
fwd.AddFunction(plugin, GetNativeFunction(2));
|
||||
g_PropData[client].Selector.SetOnEnd(fwd);
|
||||
return 0;
|
||||
}
|
||||
int Native_Selector_SetOnPreSelect(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
PrivateForward fwd = new PrivateForward(ET_Single, Param_Cell, Param_Cell);
|
||||
if(!fwd.AddFunction(plugin, GetNativeFunction(2))) return 0;
|
||||
g_PropData[client].Selector.SetOnPreSelect(fwd);
|
||||
return 1;
|
||||
}
|
||||
int Native_Selector_SetOnPostSelect(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell);
|
||||
if(!fwd.AddFunction(plugin, GetNativeFunction(2))) return 0;
|
||||
g_PropData[client].Selector.SetOnPostSelect(fwd);
|
||||
return 1;
|
||||
}
|
||||
int Native_Selector_SetOnUnselect(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell);
|
||||
if(!fwd.AddFunction(plugin, GetNativeFunction(2))) return 0;
|
||||
g_PropData[client].Selector.SetOnUnselect(fwd);
|
||||
return 1;
|
||||
}
|
||||
int Native_Selector_AddEntity(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
int entity = GetNativeCell(2);
|
||||
g_PropData[client].Selector.AddEntity(entity, false);
|
||||
return 0;
|
||||
}
|
||||
int Native_Selector_RemoveEntity(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
int entity = GetNativeCell(2);
|
||||
g_PropData[client].Selector.RemoveEntity(entity);
|
||||
return 0;
|
||||
}
|
||||
int Native_Selector_Cancel(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
g_PropData[client].Selector.Cancel();
|
||||
return 0;
|
||||
}
|
||||
int Native_Selector_End(Handle plugin, int numParams) {
|
||||
int client = GetNativeCell(1);
|
||||
g_PropData[client].Selector.End();
|
||||
return 0;
|
||||
}
|
|
@ -25,6 +25,8 @@ enum SaveType {
|
|||
Save_Schematic
|
||||
}
|
||||
|
||||
int GLOW_MANAGER[3] = { 52, 174, 235 };
|
||||
|
||||
enum struct Schematic {
|
||||
char name[64];
|
||||
char creatorSteamid[32];
|
||||
|
@ -134,6 +136,197 @@ public any Native_SpawnSchematic(Handle plugin, int numParams) {
|
|||
delete list;
|
||||
return true;
|
||||
}
|
||||
|
||||
enum struct PropSelectorIterator {
|
||||
ArrayList _list;
|
||||
int _index;
|
||||
int Entity;
|
||||
|
||||
void _Init(ArrayList list) {
|
||||
this._list = list;
|
||||
this._index = -1;
|
||||
}
|
||||
|
||||
bool Next() {
|
||||
this._index++;
|
||||
return this._index + 1 < this._list.Length;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
enum struct PropSelector {
|
||||
int selectColor[3];
|
||||
int limit;
|
||||
ArrayList list;
|
||||
PrivateForward endCallback;
|
||||
PrivateForward selectPreCallback;
|
||||
PrivateForward selectPostCallback;
|
||||
PrivateForward unSelectCallback;
|
||||
int _client;
|
||||
|
||||
PropSelectorIterator Iter() {
|
||||
PropSelectorIterator iter;
|
||||
iter._Init(this.list);
|
||||
return iter;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
if(this.endCallback) delete this.endCallback;
|
||||
if(this.selectPreCallback) delete this.selectPreCallback;
|
||||
if(this.selectPostCallback) delete this.selectPostCallback;
|
||||
if(this.unSelectCallback) delete this.unSelectCallback;
|
||||
if(this.list) delete this.list;
|
||||
}
|
||||
|
||||
void Start(int color[3], int flags = 0, int limit = 0) {
|
||||
this.selectColor = color;
|
||||
this.limit = 0;
|
||||
this.list = new ArrayList();
|
||||
SendEditorMessage(this._client, "Left click to select, right click to unselect");
|
||||
SendEditorMessage(this._client, "Press WALK+USE to confirm, DUCK+USE to cancel");
|
||||
}
|
||||
|
||||
void SetOnEnd(PrivateForward callback) {
|
||||
this.endCallback = callback;
|
||||
}
|
||||
void SetOnPreSelect(PrivateForward callback) {
|
||||
this.selectPreCallback = callback;
|
||||
}
|
||||
void SetOnPostSelect(PrivateForward callback) {
|
||||
this.selectPostCallback = callback;
|
||||
}
|
||||
void SetOnUnselect(PrivateForward callback) {
|
||||
this.unSelectCallback = callback;
|
||||
}
|
||||
|
||||
void StartDirect(int color[3], SelectDoneCallback callback, int limit = 0) {
|
||||
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell);
|
||||
fwd.AddFunction(INVALID_HANDLE, callback);
|
||||
this.Start(color, 0, limit);
|
||||
this.SetOnEnd(fwd);
|
||||
}
|
||||
|
||||
bool IsActive() {
|
||||
return this.list != null;
|
||||
}
|
||||
|
||||
void End() {
|
||||
if(this.list == null) return;
|
||||
SendEditorMessage(this._client, "Selection completed");
|
||||
// Reset glows, remove selection from our spawned props
|
||||
for(int i = 0; i < this.list.Length; i++) {
|
||||
int ref = this.list.Get(i);
|
||||
if(IsValidEntity(ref)) {
|
||||
L4D2_RemoveEntityGlow(ref);
|
||||
RemoveSpawnedProp(ref);
|
||||
}
|
||||
}
|
||||
if(this.endCallback) {
|
||||
if(GetForwardFunctionCount(this.endCallback) == 0) {
|
||||
PrintToServer("[Editor] Warn: Selector.End(): callback has no functions assigned to it.");
|
||||
}
|
||||
Call_StartForward(this.endCallback);
|
||||
Call_PushCell(this._client);
|
||||
Call_PushCell(this.list.Clone());
|
||||
int result = Call_Finish();
|
||||
if(result != SP_ERROR_NONE) {
|
||||
PrintToServer("[Editor] Warn: Selector.End() forward error: %d", result);
|
||||
}
|
||||
} else {
|
||||
PrintToServer("[Editor] Warn: Selector.End() called but no callback assigned, voiding list");
|
||||
}
|
||||
this.Reset();
|
||||
}
|
||||
|
||||
void Cancel() {
|
||||
if(this.endCallback) {
|
||||
Call_StartForward(this.endCallback);
|
||||
Call_PushCell(this._client);
|
||||
Call_PushCell(INVALID_HANDLE);
|
||||
Call_Finish();
|
||||
}
|
||||
if(this.list) {
|
||||
for(int i = 0; i < this.list.Length; i++) {
|
||||
int ref = this.list.Get(i);
|
||||
L4D2_RemoveEntityGlow(ref);
|
||||
}
|
||||
}
|
||||
PrintToChat(this._client, "\x04[Editor]\x01 Selection cancelled.");
|
||||
this.Reset();
|
||||
}
|
||||
|
||||
int GetEntityRefIndex(int ref) {
|
||||
int index = this.list.FindValue(ref);
|
||||
if(index > -1) {
|
||||
return index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Removes entity from list
|
||||
* @return returns entity ref of entity removed
|
||||
*/
|
||||
int RemoveEntity(int entity) {
|
||||
if(this.list == null) return -2;
|
||||
|
||||
L4D2_RemoveEntityGlow(entity);
|
||||
int ref = EntIndexToEntRef(entity);
|
||||
int index = this.GetEntityRefIndex(ref);
|
||||
if(index > -1) {
|
||||
this.list.Erase(index);
|
||||
if(this.unSelectCallback != null) {
|
||||
Call_StartForward(this.unSelectCallback)
|
||||
Call_PushCell(this._client);
|
||||
Call_PushCell(EntRefToEntIndex(ref));
|
||||
Call_Finish();
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
return INVALID_ENT_REFERENCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds entity to list
|
||||
* @return index into list of entity
|
||||
* @return -1 if already added
|
||||
* @return -2 if callback rejected
|
||||
*/
|
||||
int AddEntity(int entity, bool useCallback = true) {
|
||||
if(this.list == null) return -2;
|
||||
|
||||
int ref = EntIndexToEntRef(entity);
|
||||
if(this.GetEntityRefIndex(ref) == -1) {
|
||||
PrintToServer("Selector.AddEntity: PRE CALLBACK");
|
||||
// FIXME: crashes server, sourcemod bug
|
||||
/*if(this.selectPreCallback != null && useCallback) {
|
||||
Call_StartForward(this.selectPreCallback)
|
||||
Call_PushCell(this._client);
|
||||
Call_PushCell(entity);
|
||||
bool allowed = true;
|
||||
PrintToServer("Selector.AddEntity: PRE CALLBACK pre finish");
|
||||
Call_Finish(allowed);
|
||||
PrintToServer("Selector.AddEntity: PRE CALLBACK pre result %b", allowed);
|
||||
if(!allowed) return -2;
|
||||
}*/
|
||||
|
||||
L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, this.selectColor, false);
|
||||
int index = this.list.Push(ref);
|
||||
PrintToServer("Selector.AddEntity: post CALLBACK pre");
|
||||
//FIXME: crashes server, sourcemod bug
|
||||
/*if(this.selectPostCallback != null && useCallback) {
|
||||
Call_StartForward(this.selectPostCallback)
|
||||
Call_PushCell(this._client);
|
||||
Call_PushCell(entity);
|
||||
//Call_PushCell(index);
|
||||
Call_Finish();
|
||||
}*/
|
||||
PrintToServer("Selector.AddEntity: post CALLBACK post");
|
||||
return index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
enum struct PlayerPropData {
|
||||
ArrayList categoryStack;
|
||||
ArrayList itemBuffer;
|
||||
|
@ -144,14 +337,19 @@ enum struct PlayerPropData {
|
|||
int lastActiveTime;
|
||||
char classnameOverride[64];
|
||||
ChatPrompt chatPrompt;
|
||||
ArrayList markedProps;
|
||||
PropSelector Selector;
|
||||
SaveType pendingSaveType;
|
||||
|
||||
Schematic schematic;
|
||||
int highlightedEntityRef;
|
||||
int managerEntityRef;
|
||||
|
||||
void Init(int client) {
|
||||
this.Selector._client = client;
|
||||
}
|
||||
// Called on PlayerDisconnect
|
||||
void Reset() {
|
||||
if(this.markedProps != null) delete this.markedProps;
|
||||
if(this.Selector.IsActive()) this.Selector.Cancel();
|
||||
this.chatPrompt = Prompt_None;
|
||||
this.clearListBuffer = false;
|
||||
this.lastCategoryIndex = 0;
|
||||
|
@ -161,6 +359,19 @@ enum struct PlayerPropData {
|
|||
this.CleanupBuffers();
|
||||
this.pendingSaveType = Save_None;
|
||||
this.schematic.Reset();
|
||||
this.managerEntityRef = INVALID_ENT_REFERENCE;
|
||||
this.StopHighlight();
|
||||
}
|
||||
|
||||
void StartHighlight(int entity) {
|
||||
this.highlightedEntityRef = EntIndexToEntRef(entity);
|
||||
L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, GLOW_MANAGER, false);
|
||||
}
|
||||
void StopHighlight() {
|
||||
if(IsValidEntity(this.highlightedEntityRef)) {
|
||||
L4D2_RemoveEntityGlow(this.highlightedEntityRef);
|
||||
}
|
||||
this.highlightedEntityRef = INVALID_ENT_REFERENCE;
|
||||
}
|
||||
|
||||
void StartSchematic(int client, const char[] name) {
|
||||
|
|
|
@ -8,6 +8,8 @@ public void OnAdminMenuReady(Handle topMenuHandle) {
|
|||
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");
|
||||
topMenu.AddItem("editor_manager", AdminMenu_Manager, g_propSpawnerCategory, "sm_prop");
|
||||
topMenu.AddItem("editor_selector", AdminMenu_Selector, g_propSpawnerCategory, "sm_prop");
|
||||
}
|
||||
g_topMenu = topMenu;
|
||||
}
|
||||
|
@ -24,6 +26,15 @@ void Category_Handler(TopMenu topmenu, TopMenuAction action, TopMenuObject topob
|
|||
}
|
||||
}
|
||||
|
||||
void AdminMenu_Selector(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
|
||||
if(action == TopMenuAction_DisplayOption) {
|
||||
Format(buffer, maxlength, "Selector");
|
||||
} else if(action == TopMenuAction_SelectOption) {
|
||||
ShowManagerSelectorMenu(param);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
|
@ -79,6 +90,14 @@ void AdminMenu_SaveLoad(TopMenu topmenu, TopMenuAction action, TopMenuObject obj
|
|||
}
|
||||
}
|
||||
|
||||
void AdminMenu_Manager(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
|
||||
if(action == TopMenuAction_DisplayOption) {
|
||||
Format(buffer, maxlength, "Manager (ALPHA)");
|
||||
} else if(action == TopMenuAction_SelectOption) {
|
||||
Spawn_ShowManagerMainMenu(param);
|
||||
}
|
||||
}
|
||||
|
||||
int SaveLoadMainMenuHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[2];
|
||||
|
@ -87,7 +106,7 @@ int SaveLoadMainMenuHandler(Menu menu, MenuAction action, int client, int param2
|
|||
ShowSaves(client, type);
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
Spawn_ShowSaveLoadMainMenu(client);
|
||||
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
|
@ -127,6 +146,7 @@ int SaveLoadSceneHandler(Menu menu, MenuAction action, int client, int param2) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int SaveLoadSchematicHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char saveName[64];
|
||||
|
@ -189,40 +209,160 @@ int SaveLoadConfirmHandler(Menu menu, MenuAction action, int client, int param2)
|
|||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DeleteHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
int ManagerHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[8];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
if(info[0] != '\0') {
|
||||
int index = StringToInt(info);
|
||||
if(index == -1) {
|
||||
int ref = g_spawnedItems.Get(index);
|
||||
// TODO: add delete confirm
|
||||
if(!IsValidEntity(ref)) {
|
||||
SendEditorMessage(client, "Entity has disappeared");
|
||||
} else {
|
||||
int entity = EntRefToEntIndex(ref);
|
||||
g_PropData[client].managerEntityRef = ref;
|
||||
g_PropData[client].StartHighlight(entity);
|
||||
ShowManagerEntityMenu(client, entity);
|
||||
}
|
||||
}
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
Spawn_ShowSaveLoadMainMenu(client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
int ManagerEntityHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
g_PropData[client].StopHighlight();
|
||||
char info[32];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
int ref = g_PropData[client].managerEntityRef;
|
||||
if(!IsValidEntity(ref)) {
|
||||
SendEditorMessage(client, "Entity disappeared");
|
||||
return 0;
|
||||
}
|
||||
if(StrEqual(info, "edit")) {
|
||||
Editor[client].ImportEntity(EntRefToEntIndex(ref), Edit_Manager);
|
||||
Spawn_ShowManagerMainMenu(client);
|
||||
} else if(StrEqual(info, "delete")) {
|
||||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||
int spawnedRef = g_spawnedItems.Get(i);
|
||||
if(spawnedRef == ref) {
|
||||
g_spawnedItems.Erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(IsValidEntity(ref)) {
|
||||
RemoveEntity(ref);
|
||||
}
|
||||
Spawn_ShowManagerMainMenu(client);
|
||||
} else if(StrEqual(info, "view")) {
|
||||
ReplyToCommand(client, "Maybe soon.");
|
||||
} else if(StrEqual(info, "select")) {
|
||||
ShowManagerSelectorMenu(client);
|
||||
int entity = EntRefToEntIndex(ref);
|
||||
g_PropData[client].Selector.AddEntity(entity);
|
||||
} else {
|
||||
SendEditorMessage(client, "Unknown option / not implemented");
|
||||
}
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
g_PropData[client].StopHighlight();
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
Spawn_ShowManagerMainMenu(client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
int ManagerSelectorMainMenuHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
if(!EntitySelector.FromClient(client).Active) {
|
||||
return 0;
|
||||
}
|
||||
char info[32];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
if(StrEqual(info, "list")) {
|
||||
SendEditorMessage(client, "Not implemented");
|
||||
} else if(StrEqual(info, "actions")) {
|
||||
ShowManagerSelectorActionsMenu(client);
|
||||
} else if(StrEqual(info, "cancel")) {
|
||||
g_PropData[client].Selector.Cancel();
|
||||
}
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
g_PropData[client].Selector.Cancel();
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
int ManagerSelectorActionHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
if(!g_PropData[client].Selector.IsActive()) {
|
||||
return 0;
|
||||
}
|
||||
char info[32];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
if(StrEqual(info, "delete")) {
|
||||
for(int i = 0; i < g_PropData[client].Selector.list.Length; i++) {
|
||||
int ref = g_PropData[client].Selector.list.Get(i);
|
||||
if(IsValidEntity(ref)) {
|
||||
RemoveEntity(ref);
|
||||
}
|
||||
}
|
||||
g_PropData[client].Selector.End();
|
||||
Spawn_ShowManagerMainMenu(client);
|
||||
} else if(StrEqual(info, "save")) {
|
||||
// TODO: implement
|
||||
SendEditorMessage(client, "Not implemented");
|
||||
} else {
|
||||
SendEditorMessage(client, "Unknown option / not implemented");
|
||||
}
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
Spawn_ShowSaveLoadMainMenu(client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
int COLOR_DELETE[3] = { 255, 0, 0 }
|
||||
|
||||
int DeleteHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[128];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
int ref = StringToInt(info[2]);
|
||||
int option = StringToInt(info);
|
||||
if(option == -1) {
|
||||
// Delete all (everyone)
|
||||
int count = DeleteAll();
|
||||
PrintToChat(client, "\x04[Editor]\x01 Deleted \x05%d\x01 items", count);
|
||||
ShowDeleteList(client);
|
||||
} else if(index == -2) {
|
||||
} else if(option == -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 if(option == -3) {
|
||||
if(g_PropData[client].Selector.IsActive()) {
|
||||
g_PropData[client].Selector.End();
|
||||
PrintToChat(client, "\x04[Editor]\x01 Delete tool cancelled");
|
||||
} else {
|
||||
g_PropData[client].markedProps = new ArrayList();
|
||||
g_PropData[client].Selector.StartDirect(COLOR_DELETE, OnDeleteToolEnd);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Delete tool active. Press \x05Left Mouse\x01 to mark props, \x05Right Mouse\x01 to undo. SHIFT+USE to spawn, CTRL+USE to cancel");
|
||||
}
|
||||
ShowDeleteList(client);
|
||||
} else {
|
||||
int ref = g_spawnedItems.Get(index);
|
||||
// TODO: add delete confirm
|
||||
int index = g_spawnedItems.FindValue(ref);
|
||||
if(IsValidEntity(ref)) {
|
||||
RemoveEntity(ref);
|
||||
}
|
||||
if(index > -1) {
|
||||
g_spawnedItems.Erase(index);
|
||||
if(index > 0) {
|
||||
index--;
|
||||
}
|
||||
} else { index = 0; }
|
||||
ShowDeleteList(client, index);
|
||||
}
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
|
@ -317,16 +457,18 @@ 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 ref = StringToInt(info);
|
||||
int index = g_spawnedItems.FindValue(ref);
|
||||
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.");
|
||||
if(index > -1) {
|
||||
g_spawnedItems.Erase(index);
|
||||
index--;
|
||||
} else { index = 0; }
|
||||
}
|
||||
ShowEditList(client, index);
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
/////////////
|
||||
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.SetTitle("Choose spawn list:");
|
||||
menu.AddItem("f", "Favorites (Broken :D)");
|
||||
menu.AddItem("r", "Recently Spawned Props");
|
||||
menu.AddItem("s", "Search for Props");
|
||||
menu.AddItem("n", "Browse Props");
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
menu.Display(client, MENU_TIME_FOREVER);
|
||||
|
@ -17,6 +17,7 @@ void Spawn_ShowRecents(int client) {
|
|||
ArrayList items = GetRecentsItemList();
|
||||
if(items.Length == 0) {
|
||||
CReplyToCommand(client, "\x04[Editor] \x01No recent props spawned.");
|
||||
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
|
||||
return;
|
||||
}
|
||||
ShowTempItemMenu(client, items, "Recents");
|
||||
|
@ -26,6 +27,11 @@ void Spawn_ShowSearch(int client) {
|
|||
CReplyToCommand(client, "\x04[Editor] \x01Please enter search query in chat:");
|
||||
}
|
||||
void ShowDeleteList(int client, int index = -3) {
|
||||
if(g_spawnedItems.Length == 0) {
|
||||
SendEditorMessage(client, "No spawned items to delete");
|
||||
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
|
||||
return;
|
||||
}
|
||||
Menu menu = new Menu(DeleteHandler);
|
||||
menu.SetTitle("Delete Props");
|
||||
|
||||
|
@ -38,7 +44,7 @@ void ShowDeleteList(int client, int index = -3) {
|
|||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||
int ref = GetSpawnedItem(i);
|
||||
if(ref == -1) continue;
|
||||
IntToString(i, info, sizeof(info));
|
||||
Format(info, sizeof(info), "0|%d", ref);
|
||||
GetEntPropString(ref, Prop_Data, "m_ModelName", buffer, sizeof(buffer));
|
||||
index = FindCharInString(buffer, '/', true);
|
||||
if(index != -1)
|
||||
|
@ -52,6 +58,11 @@ void ShowDeleteList(int client, int index = -3) {
|
|||
menu.DisplayAt(client, 0, MENU_TIME_FOREVER);
|
||||
}
|
||||
void ShowEditList(int client, int index = 0) {
|
||||
if(g_spawnedItems.Length == 0) {
|
||||
SendEditorMessage(client, "No spawned items to edit");
|
||||
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
|
||||
return;
|
||||
}
|
||||
Menu menu = new Menu(EditHandler);
|
||||
menu.SetTitle("Edit Prop");
|
||||
|
||||
|
@ -60,7 +71,7 @@ void ShowEditList(int client, int index = 0) {
|
|||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||
int ref = GetSpawnedItem(i);
|
||||
if(ref == -1) continue;
|
||||
IntToString(i, info, sizeof(info));
|
||||
Format(info, sizeof(info), "%d", ref);
|
||||
GetEntPropString(ref, Prop_Data, "m_ModelName", buffer, sizeof(buffer));
|
||||
index = FindCharInString(buffer, '/', true);
|
||||
if(index != -1)
|
||||
|
@ -104,6 +115,8 @@ void _showItemMenu(int client, ArrayList items, const char[] title = "", bool cl
|
|||
items = g_PropData[client].itemBuffer;
|
||||
if(items == null) {
|
||||
LogError("Previous list does not exist and no new list was provided ShowItemMenu(%N)", client);
|
||||
PrintToChat(client, "\x04[Editor]\x01 An error occurred (no list)");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Populate the buffer with this list
|
||||
|
@ -194,6 +207,81 @@ void Spawn_ShowSaveLoadMainMenu(int client) {
|
|||
menu.Display(client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
||||
void Spawn_ShowManagerMainMenu(int client, int index = 0) {
|
||||
if(g_spawnedItems.Length == 0) {
|
||||
SendEditorMessage(client, "No spawned items to manage");
|
||||
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
|
||||
return;
|
||||
}
|
||||
Menu menu = new Menu(ManagerHandler);
|
||||
menu.SetTitle("Manager");
|
||||
// Id is SaveType
|
||||
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;
|
||||
menu.DisplayAt(client, index, MENU_TIME_FOREVER);
|
||||
}
|
||||
void ShowManagerEntityMenu(int client, int entity) {
|
||||
if(!IsValidEntity(entity)) {
|
||||
SendEditorMessage(client, "Item has vanished");
|
||||
Spawn_ShowManagerMainMenu(client);
|
||||
return;
|
||||
}
|
||||
Menu menu = new Menu(ManagerEntityHandler);
|
||||
menu.SetTitle("Manage %d", entity);
|
||||
menu.AddItem("edit", "Edit");
|
||||
menu.AddItem("delete", "Delete");
|
||||
menu.AddItem("select", "Select");
|
||||
menu.AddItem("view", "View");
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
menu.Display(client, MENU_TIME_FOREVER);
|
||||
}
|
||||
void ShowManagerSelectorMenu(int client) {
|
||||
EntitySelector sel = EntitySelector.FromClient(client);
|
||||
if(!sel.Active) {
|
||||
sel.Start(GLOW_MANAGER);
|
||||
sel.SetOnEnd(OnManagerSelectorEnd);
|
||||
sel.SetOnPostSelect(OnManagerSelectorSelect);
|
||||
sel.SetOnUnselect(OnManagerSelectorSelect);
|
||||
}
|
||||
Menu menu = new Menu(ManagerSelectorMainMenuHandler);
|
||||
menu.SetTitle("Selector");
|
||||
menu.AddItem("list", "> List Entities");
|
||||
menu.AddItem("actions", "> Actions");
|
||||
menu.AddItem("add-self", "Add All Self-Spawned");
|
||||
menu.AddItem("add-all", "Add All Spawned");
|
||||
menu.ExitBackButton = false;
|
||||
menu.ExitButton = true;
|
||||
menu.Display(client, MENU_TIME_FOREVER);
|
||||
}
|
||||
void ShowManagerSelectorActionsMenu(int client) {
|
||||
Menu menu = new Menu(ManagerSelectorActionHandler);
|
||||
menu.SetTitle("Selector: Select action");
|
||||
char display[32];
|
||||
Format(display, sizeof(display), "Entities: %d", g_PropData[client].Selector.list.Length);
|
||||
menu.AddItem("", display, ITEMDRAW_DISABLED);
|
||||
|
||||
// menu.AddItem("edit", "Edit");
|
||||
menu.AddItem("delete", "Delete");
|
||||
// menu.AddItem("select", "Select");
|
||||
menu.AddItem("save", "Save");
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
menu.Display(client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
||||
void ShowSaves(int client, SaveType type) {
|
||||
ArrayList saves;
|
||||
Menu newMenu;
|
||||
|
|
|
@ -378,9 +378,7 @@ ArrayList SearchItems(const char[] query) {
|
|||
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;
|
||||
|
@ -446,26 +444,28 @@ bool RemoveSpawnedProp(int ref) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void EndDeleteTool(int client, bool deleteEntities = false) {
|
||||
if(g_PropData[client].markedProps != null) {
|
||||
void OnDeleteToolEnd(int client, ArrayList entities) {
|
||||
int count;
|
||||
for(int i = 0; i < g_PropData[client].markedProps.Length; i++) {
|
||||
int ref = g_PropData[client].markedProps.Get(i);
|
||||
for(int i = 0; i < entities.Length; i++) {
|
||||
int ref = entities.Get(i);
|
||||
if(IsValidEntity(ref)) {
|
||||
count++;
|
||||
if(deleteEntities) {
|
||||
RemoveSpawnedProp(ref);
|
||||
RemoveEntity(ref);
|
||||
}
|
||||
else L4D2_RemoveEntityGlow(EntRefToEntIndex(ref));
|
||||
}
|
||||
}
|
||||
delete g_PropData[client].markedProps;
|
||||
if(deleteEntities)
|
||||
delete entities;
|
||||
PrintToChat(client, "\x04[Editor]\x01 \x05%d\x01 entities deleted", count);
|
||||
else
|
||||
PrintToChat(client, "\x04[Editor]\x01 Delete tool cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
void OnManagerSelectorEnd(int client, ArrayList entities) {
|
||||
// TODO: implement manager selector cb
|
||||
ReplyToCommand(client, "Not Implemented");
|
||||
delete entities;
|
||||
}
|
||||
void OnManagerSelectorSelect(int client, int entity) {
|
||||
// update entity count
|
||||
ShowManagerSelectorMenu(client);
|
||||
}
|
||||
|
||||
int DeleteAll(int onlyPlayer = 0) {
|
||||
|
|
155
scripting/include/hats_editor.inc
Normal file
155
scripting/include/hats_editor.inc
Normal file
|
@ -0,0 +1,155 @@
|
|||
#if defined _editor_included_
|
||||
#endinput
|
||||
#endif
|
||||
#define _editor_included_
|
||||
|
||||
public SharedPlugin __pl_editor_ = {
|
||||
name = "editor",
|
||||
file = "hats.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_editor__SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("SpawnSchematic");
|
||||
MarkNativeAsOptional("StartEdit");
|
||||
MarkNativeAsOptional("StartSpawner");
|
||||
MarkNativeAsOptional("CancelEdit");
|
||||
MarkNativeAsOptional("IsEditorActive");
|
||||
|
||||
MarkNativeAsOptional("StartSelector");
|
||||
MarkNativeAsOptional("CancelSelector");
|
||||
MarkNativeAsOptional("IsSelectorActive");
|
||||
|
||||
MarkNativeAsOptional("Selector.Count.get");
|
||||
MarkNativeAsOptional("Selector.Active.get");
|
||||
MarkNativeAsOptional("Selector.Start");
|
||||
MarkNativeAsOptional("Selector.SetOnEnd");
|
||||
MarkNativeAsOptional("Selector.SetOnPreSelect");
|
||||
MarkNativeAsOptional("Selector.SetOnPostSelect");
|
||||
MarkNativeAsOptional("Selector.SetOnUnselect");
|
||||
MarkNativeAsOptional("Selector.AddEntity");
|
||||
MarkNativeAsOptional("Selector.RemoveEntity");
|
||||
MarkNativeAsOptional("Selector.Cancel");
|
||||
MarkNativeAsOptional("Selector.End");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
native bool SpawnSchematic(const char name[32], const float pos[3], const float angles[3] = NULL_VECTOR);
|
||||
|
||||
/** Called when edit is done or cancelled
|
||||
* @param client - client doing the edit
|
||||
* @param entity - The entity edited
|
||||
* @param result - Result of the edit, or cancelled
|
||||
* @return boolean - only for StartSpawner, true to continue, false to end spawning
|
||||
*/
|
||||
typeset EditorDoneCallback {
|
||||
function void (int client, int entity, CompleteType result);
|
||||
function bool (int client, int entity, CompleteType result);
|
||||
}
|
||||
|
||||
/** Called when an item is to be selected.
|
||||
* @return boolean - TRUE to allow item to be selected, FALSE to reject
|
||||
*/
|
||||
typedef SelectPreAddCallback = function bool (int client, int entity);
|
||||
/** Called when an item has been selected */
|
||||
typedef SelectPostAddCallback = function void (int client, int entity);
|
||||
|
||||
/** Called when an item is to be unselected. */
|
||||
typedef SelectRemoveCallback = function void (int client, int entity);
|
||||
/** Called when a user is done selecting items
|
||||
* @param client - client doing the selection
|
||||
* @param entities - if null, selection was cancelled. if not null, contains list of entity references, must be deleted.
|
||||
*/
|
||||
typedef SelectDoneCallback = function void (int client, ArrayList entities);
|
||||
|
||||
/** Starts editing an entity
|
||||
* @param client - The client that is editing
|
||||
* @param entity - The entity to edit
|
||||
* @param doneCallback - Called when edit is done
|
||||
*/
|
||||
native void StartEdit(int client, int entity, EditorDoneCallback doneCallback);
|
||||
/** Let client pick prop(s) to spawn
|
||||
* @param client - The client that is editing
|
||||
* @param entity - The entity to edit
|
||||
* @param doneCallback - Called when edit is done
|
||||
*/
|
||||
native void StartSpawner(int client, EditorDoneCallback doneCallback);
|
||||
native void CancelEdit(int client);
|
||||
// Includes non-plugin started edits
|
||||
native bool IsEditorActive(int client);
|
||||
|
||||
/** Starts a selection, where the client can click on entities to select or deselect them.
|
||||
* @param client - the client that can select
|
||||
* @param callback - called when user is done seleting or cancelled
|
||||
* @param highlightColor - the color to highlight selected items, default solid green
|
||||
* @param maxEntities - the max number of selections, 0 for infinite
|
||||
*/
|
||||
native void StartSelector(int client, SelectDoneCallback callback, int highlightColor[3] = { 0, 255, 0 }, int maxEntities = 0);
|
||||
|
||||
methodmap EntitySelector {
|
||||
public EntitySelector(int client) {
|
||||
return view_as<EntitySelector>(client);
|
||||
}
|
||||
|
||||
public static EntitySelector FromClient(int client) {
|
||||
return view_as<EntitySelector>(client);
|
||||
}
|
||||
|
||||
/** Starts a new selector for client
|
||||
* @param highlightColor - the color to highlight selected items, default solid green
|
||||
* @param flags - not used.
|
||||
* @param maxEntities - the max number of selections, 0 for infinite
|
||||
*/
|
||||
public native EntitySelector Start(int highlightColor[3], int flags = 0, int maxEntities = 0);
|
||||
|
||||
|
||||
property int Count {
|
||||
/** Returns the number of entities in selector. Returns -1 if not active */
|
||||
public native get();
|
||||
}
|
||||
|
||||
property bool Active {
|
||||
public native get();
|
||||
}
|
||||
|
||||
/** Sets the callback for when the selector is ended (or cancelled) */
|
||||
public native void SetOnEnd(SelectDoneCallback callback);
|
||||
|
||||
/** Sets the callback for when an item is to be added to the selector. */
|
||||
public native void SetOnPreSelect(SelectPreAddCallback callback);
|
||||
|
||||
/** Sets the callback for when an item has been added to the selector. */
|
||||
public native void SetOnPostSelect(SelectPostAddCallback callback);
|
||||
|
||||
/** Sets the callback for when an item is removed from selector. */
|
||||
public native void SetOnUnselect(SelectRemoveCallback callback);
|
||||
|
||||
/** Adds an entity to selection. Does not call SelectAddCallback */
|
||||
public native void AddEntity(int entity);
|
||||
|
||||
/** Removes an entity from selection. Does not call SelectAddCallback */
|
||||
public native void RemoveEntity(int entity);
|
||||
|
||||
public native void Cancel();
|
||||
|
||||
public native void End();
|
||||
}
|
||||
|
||||
|
||||
native void CancelSelector(int client);
|
||||
native bool IsSelectorActive(int client);
|
||||
|
||||
enum CompleteType {
|
||||
Complete_WallSuccess,
|
||||
Complete_WallError,
|
||||
Complete_PropSpawned,
|
||||
Complete_PropError,
|
||||
Complete_EditSuccess
|
||||
}
|
|
@ -2,21 +2,50 @@
|
|||
#endinput
|
||||
#endif
|
||||
#define _overlay_included
|
||||
#include <ripext>
|
||||
|
||||
native bool SendTempUI(int client, const char[] id, int lifetime, JSONObject element);
|
||||
public SharedPlugin __pl_overlay = {
|
||||
name = "overlay",
|
||||
file = "overlay.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
native bool ShowUI(int client, const char[] elemNamespace, const char[] elemId, JSONObject variables);
|
||||
#define ACTION_ARG_LENGTH 128 // The length each arg (separated by space) can be
|
||||
|
||||
native bool HideUI(int client, const char[] elemNamespace, const char[] elemId);
|
||||
// typedef ActionFallbackHandlerCallback = function void (const char[] actionName, const char[][] args, int numArgs);
|
||||
// typedef ActionHandlerCallback = function void (const char[][] args, int numArgs);
|
||||
typedef ActionFallbackHandlerCallback = function void (const char[] actionName, UIActionEvent event, int client);
|
||||
typedef ActionHandlerCallback = function void (UIActionEvent event, int client);
|
||||
|
||||
native bool PlayAudio(int client, const char[] url);
|
||||
|
||||
native bool IsOverlayConnected();
|
||||
|
||||
forward void OnUIAction(const char[] elemNamespace, const char[] elemId, const char[] action);
|
||||
// myplugin:action_name
|
||||
// Handles any action for actionNamespace and actionName
|
||||
native void RegisterActionHandler(const char[] actionNamespace, const char[] actionName, ActionFallbackHandlerCallback cb);
|
||||
// Handles all actions for namespace that were not caught by RegisterActionHandler
|
||||
native void RegisterActionAnyHandler(const char[] actionNamespace, ActionHandlerCallback cb);
|
||||
|
||||
typedef UIActionCallback = function void (const char[][] args, int numArgs);
|
||||
methodmap UIActionEvent {
|
||||
public UIActionEvent(ArrayList list) {
|
||||
return view_as<UIActionEvent>(list);
|
||||
}
|
||||
|
||||
public void GetArg(int argNum, char[] output, int maxlen) {
|
||||
view_as<ArrayList>(this).GetString(argNum, output, maxlen);
|
||||
}
|
||||
|
||||
public void _Delete() {
|
||||
delete view_as<ArrayList>(this);
|
||||
}
|
||||
|
||||
property int Args {
|
||||
public get() { return view_as<ArrayList>(this).Length; }
|
||||
}
|
||||
}
|
||||
|
||||
methodmap UIElement < JSONObject {
|
||||
public UIElement(const char[] elemNamespace, const char[] elemId) {
|
||||
|
@ -24,6 +53,7 @@ methodmap UIElement < JSONObject {
|
|||
obj.SetString("namespace", elemNamespace);
|
||||
obj.SetString("elem_id", elemId);
|
||||
obj.SetBool("visibility", false);
|
||||
obj.Set("steamids", new JSONArray());
|
||||
obj.Set("variables", new JSONObject());
|
||||
|
||||
return view_as<UIElement>(obj);
|
||||
|
@ -35,16 +65,6 @@ methodmap UIElement < JSONObject {
|
|||
}
|
||||
public set(bool value) {
|
||||
view_as<JSONObject>(this).SetBool("visibility", value);
|
||||
this.Send();
|
||||
}
|
||||
}
|
||||
|
||||
/** Is the UI element globally sent to all connected players?
|
||||
* Specify players with .AddClient() or clear with .ClearClients()
|
||||
*/
|
||||
property bool Global {
|
||||
public get() {
|
||||
return !view_as<JSONObject>(this).HasKey("steamids")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,35 +88,13 @@ methodmap UIElement < JSONObject {
|
|||
view_as<JSONObject>(this).SetBool(id, value);
|
||||
}
|
||||
|
||||
public void SetActionCallback(UIActionCallback callback) {}
|
||||
|
||||
public void AddClient(const char[] steamid) {
|
||||
// if(!IsClientInGame(client) || steamidCache[client][0] == '\0') ThrowError("Client %d is not connected, ingame, or authorized");
|
||||
JSONObject obj = view_as<JSONObject>(this);
|
||||
JSONArray steamids = view_as<JSONArray>(obj.Get("steamids"));
|
||||
if(steamids == null) {
|
||||
steamids = new JSONArray();
|
||||
obj.Set("steamids", steamids)
|
||||
public native bool SendAll();
|
||||
public native bool SendTo(int client);
|
||||
public bool SendToMultiple(int[] clientIds, int numClients) {
|
||||
for(int i = 0; i < numClients; i++) {
|
||||
this.SendTo(clientIds[i]);
|
||||
}
|
||||
steamids.PushString(steamid);
|
||||
}
|
||||
|
||||
public void ClearClients() {
|
||||
view_as<JSONObject>(this).Remove("steamids");
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
view_as<JSONObject>(this).Clear();
|
||||
}
|
||||
|
||||
public void Hide() {
|
||||
this.Visibility = false;
|
||||
}
|
||||
public void Show() {
|
||||
this.Visibility = true;
|
||||
}
|
||||
|
||||
public native bool Send();
|
||||
}
|
||||
|
||||
methodmap UIPosition < JSONObject {
|
||||
|
@ -118,6 +116,25 @@ methodmap UIPosition < JSONObject {
|
|||
}
|
||||
}
|
||||
|
||||
methodmap UISize < JSONObject {
|
||||
public UISize(int width, int height) {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.SetInt("width", width);
|
||||
obj.SetInt("height", height);
|
||||
return view_as<UISize>(obj);
|
||||
}
|
||||
|
||||
property int Width {
|
||||
public get() { return view_as<JSONObject>(this).GetInt("width"); }
|
||||
public set(int value) { view_as<JSONObject>(this).SetInt("height", value); }
|
||||
}
|
||||
|
||||
property int Height {
|
||||
public get() { return view_as<JSONObject>(this).GetInt("height"); }
|
||||
public set(int value) { view_as<JSONObject>(this).SetInt("height", value); }
|
||||
}
|
||||
}
|
||||
|
||||
methodmap UIColor < JSONObject {
|
||||
/// Creates a new UIColor with RGB between 0-255, alpha is normalized 0.0-1.0
|
||||
public UIColor(int r = 255, int g = 255, int b = 255) {
|
||||
|
@ -168,11 +185,15 @@ methodmap TempUIElementDefaults < JSONObject {
|
|||
}
|
||||
property UIPosition Position {
|
||||
public get() { return view_as<UIPosition>(view_as<JSONObject>(this).Get("position")); }
|
||||
public set(UIPosition pos) { view_as<JSONObject>(this).Set("position", view_as<JSON>(pos)); }
|
||||
// public set(UIPosition pos) { view_as<JSONObject>(this).Set("position", view_as<JSON>(pos)); }
|
||||
}
|
||||
property UIColor BackgroundColor {
|
||||
public get() { return view_as<UIColor>(view_as<JSONObject>(this).Get("bgColor")); }
|
||||
public set(UIColor color) { view_as<JSONObject>(this).Set("bgColor", view_as<JSON>(color)); }
|
||||
// public set(UIColor color) { view_as<JSONObject>(this).Set("bgColor", view_as<JSON>(color)); }
|
||||
}
|
||||
property UISize Size {
|
||||
public get() { return view_as<UISize>(view_as<JSONObject>(this).Get("size")); }
|
||||
// public set(UISize size) { view_as<JSONObject>(this).Set("size", view_as<JSON>(size)); }
|
||||
}
|
||||
/// Returns or sets opacity, -1 is not set
|
||||
property int Opacity {
|
||||
|
@ -203,6 +224,7 @@ enum UIType {
|
|||
Element_Unknown = -1,
|
||||
Element_Text,
|
||||
Element_List,
|
||||
Element_Audio
|
||||
}
|
||||
enum UIFlags {
|
||||
Element_None
|
||||
|
@ -287,27 +309,29 @@ methodmap TempUI {
|
|||
public TempUI(const char[] elemId, const char[] type, int lifetime = 0) {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.SetString("elem_id", elemId);
|
||||
obj.Set("steamids", new JSONArray());
|
||||
obj.SetInt("expires_seconds", 0);
|
||||
TempUIElement element = new TempUIElement(type);
|
||||
obj.Set("element", element);
|
||||
return view_as<TempUI>(obj);
|
||||
}
|
||||
|
||||
/// How long the temp UI lasts, 0 for never.
|
||||
property int Duration {
|
||||
public get() {
|
||||
return view_as<JSONObject>(this).GetInt("expires_seconds");
|
||||
}
|
||||
public set(int value) {
|
||||
view_as<JSONObject>(this).SetInt("expires_seconds", value);
|
||||
}
|
||||
}
|
||||
|
||||
property bool Visible {
|
||||
public get() {
|
||||
return view_as<JSONObject>(this).GetBool("visibility");
|
||||
}
|
||||
public set(bool value) {
|
||||
view_as<JSONObject>(this).SetBool("visibility", value);
|
||||
this.Send();
|
||||
}
|
||||
}
|
||||
|
||||
/** Is the UI element globally sent to all connected players?
|
||||
* Specify players with .AddClient() or clear with .ClearClients()
|
||||
*/
|
||||
property bool Global {
|
||||
public get() {
|
||||
return !view_as<JSONObject>(this).HasKey("steamids")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,38 +340,127 @@ methodmap TempUI {
|
|||
return view_as<TempUIElement>(view_as<JSONObject>(this).Get("element"));
|
||||
}
|
||||
public set(TempUIElement newElement) {
|
||||
// Delete old element
|
||||
JSON elem = view_as<JSONObject>(this).Get("element");
|
||||
if(elem != null) delete elem;
|
||||
|
||||
view_as<JSONObject>(this).Set("element", view_as<JSON>(newElement));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetActionCallback(UIActionCallback callback) {}
|
||||
|
||||
public void AddClient(const char[] steamid) {
|
||||
// if(!IsClientInGame(client) || steamidCache[client][0] == '\0') ThrowError("Client %d is not connected, ingame, or authorized");
|
||||
JSONObject obj = view_as<JSONObject>(this);
|
||||
JSONArray steamids = view_as<JSONArray>(obj.Get("steamids"));
|
||||
if(steamids == null) {
|
||||
steamids = new JSONArray();
|
||||
obj.Set("steamids", steamids)
|
||||
}
|
||||
steamids.PushString(steamid);
|
||||
}
|
||||
|
||||
public void ClearClients() {
|
||||
view_as<JSONObject>(this).Remove("steamids");
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
view_as<JSONObject>(this).Clear();
|
||||
}
|
||||
|
||||
public void Hide() {
|
||||
this.Visibility = false;
|
||||
this.Visible = false;
|
||||
}
|
||||
public void Show() {
|
||||
this.Visibility = true;
|
||||
this.Visible = true;
|
||||
}
|
||||
|
||||
public native bool Send();
|
||||
|
||||
public native bool SendAll();
|
||||
public native bool SendTo(int client);
|
||||
public bool SendToMultiple(int[] clientIds, int numClients) {
|
||||
for(int i = 0; i < numClients; i++) {
|
||||
this.SendTo(clientIds[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum AudioState {
|
||||
// Audio stopped, reset to startTime
|
||||
Audio_Stopped,
|
||||
// Pauses audio at current time
|
||||
Audio_Paused,
|
||||
Audio_Play
|
||||
}
|
||||
|
||||
methodmap ClientList < JSONArray {
|
||||
public ClientList() {
|
||||
return view_as<ClientList>(new JSONArray());
|
||||
}
|
||||
|
||||
property int Length {
|
||||
public get() { return view_as<JSONArray>(this).Length; }
|
||||
}
|
||||
|
||||
public native void AddClient(int client);
|
||||
|
||||
public native bool HasClient(int client);
|
||||
|
||||
public void Clear() {
|
||||
view_as<JSONArray>(this).Clear();
|
||||
}
|
||||
}
|
||||
|
||||
methodmap AudioResource < JSONObject {
|
||||
public AudioResource(const char[] url, float volume = 0.5) {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.SetString("source", url);
|
||||
obj.SetFloat("volume", volume);
|
||||
obj.SetInt("state", 0);
|
||||
obj.Set("steamids", new JSONArray());
|
||||
obj.SetBool("repeat", false)
|
||||
return view_as<AudioResource>(obj);
|
||||
}
|
||||
|
||||
property AudioState State {
|
||||
public get() {
|
||||
return view_as<AudioState>(view_as<JSONObject>(this).GetInt("state"));
|
||||
}
|
||||
public set(AudioState state) {
|
||||
view_as<JSONObject>(this).SetInt("state", view_as<int>(state));
|
||||
}
|
||||
}
|
||||
|
||||
property float Volume {
|
||||
public get() {
|
||||
return view_as<JSONObject>(this).GetFloat("volume");
|
||||
}
|
||||
public set(float volume) {
|
||||
view_as<JSONObject>(this).SetFloat("volume", volume);
|
||||
}
|
||||
}
|
||||
|
||||
property bool Repeat {
|
||||
public get() {
|
||||
return view_as<JSONObject>(this).GetBool("repeat");
|
||||
}
|
||||
public set(bool repeat) {
|
||||
view_as<JSONObject>(this).SetBool("repeat", repeat);
|
||||
}
|
||||
}
|
||||
|
||||
property ClientList Clients {
|
||||
public get() {
|
||||
return view_as<ClientList>(view_as<JSONObject>(this).Get("steamids"));
|
||||
}
|
||||
}
|
||||
/// Plays or resumes playing
|
||||
public native void Play();
|
||||
/// Stops playing audio, clients will reset to beginning
|
||||
public native void Stop();
|
||||
/// Pauses audio, resuming to current play duration
|
||||
public native void Pause();
|
||||
|
||||
public void Clear() {
|
||||
view_as<JSONObject>(this).Clear();
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_overlay_SetNTVOptional() {
|
||||
MarkNativeAsOptional("IsOverlayConnected");
|
||||
MarkNativeAsOptional("RegisterActionAnyHandler");
|
||||
MarkNativeAsOptional("RegisterActionHandler");
|
||||
|
||||
MarkNativeAsOptional("UIElement.SendAll");
|
||||
MarkNativeAsOptional("UIElement.SendTo");
|
||||
MarkNativeAsOptional("TempUI.SendAll");
|
||||
MarkNativeAsOptional("TempUI.SendTo");
|
||||
MarkNativeAsOptional("AudioResource.Play");
|
||||
MarkNativeAsOptional("AudioResource.Stop");
|
||||
MarkNativeAsOptional("AudioResource.Pause");
|
||||
}
|
||||
#endif
|
135
scripting/include/randomizer/rbuild.sp
Normal file
135
scripting/include/randomizer/rbuild.sp
Normal file
|
@ -0,0 +1,135 @@
|
|||
/// MENUS
|
||||
public void OpenMainMenu(int client) {
|
||||
Menu menu = new Menu(BuilderHandler_MainMenu);
|
||||
menu.SetTitle("Randomizer Builder");
|
||||
if(g_builder.mapData == null) {
|
||||
menu.AddItem("load", "Load Map Data");
|
||||
menu.AddItem("new", "New Map Data");
|
||||
} else {
|
||||
menu.AddItem("save", "Save Map Data");
|
||||
menu.AddItem("selector", "Start Selector");
|
||||
menu.AddItem("spawner", "Start Spawner");
|
||||
menu.AddItem("cursor", "Add Entity At Cursor");
|
||||
menu.AddItem("scenes", "Scenes");
|
||||
}
|
||||
menu.Display(client, 0);
|
||||
}
|
||||
|
||||
void OpenScenesMenu(int client) {
|
||||
Menu menu = new Menu(BuilderHandler_ScenesMenu);
|
||||
menu.SetTitle("Select a scene");
|
||||
char id[64], display[32];
|
||||
JSONObjectKeys iterator = g_builder.mapData.Keys();
|
||||
while(iterator.ReadKey(id, sizeof(id))) {
|
||||
if(StrEqual(id, g_builder.selectedSceneId)) {
|
||||
Format(display, sizeof(display), "%s (selected)", id);
|
||||
} else {
|
||||
Format(display, sizeof(display), "%s", id);
|
||||
}
|
||||
menu.AddItem(id, display);
|
||||
}
|
||||
menu.Display(client, 0);
|
||||
}
|
||||
|
||||
void OpenVariantsMenu(int client) {
|
||||
Menu menu = new Menu(BuilderHandler_VariantsMenu);
|
||||
menu.SetTitle("%s > Variants", g_builder.selectedSceneId);
|
||||
char id[8], display[32];
|
||||
menu.AddItem("new", "New");
|
||||
menu.AddItem("-1", "None (Shared Scene)");
|
||||
|
||||
JSONArray variants = view_as<JSONArray>(g_builder.selectedSceneData.Get("variants"));
|
||||
JSONObject varObj;
|
||||
JSONArray entities;
|
||||
for(int i = 0; i < variants.Length; i++) {
|
||||
varObj = view_as<JSONObject>(variants.Get(i));
|
||||
entities = view_as<JSONArray>(varObj.Get("entities"));
|
||||
if(i == g_builder.selectedVariantIndex) {
|
||||
Format(display, sizeof(display), "%d entities (selected)", entities.Length);
|
||||
} else {
|
||||
Format(display, sizeof(display), "%d entities", entities.Length);
|
||||
}
|
||||
IntToString(i, id, sizeof(id));
|
||||
menu.AddItem(id, display);
|
||||
}
|
||||
menu.Display(client, 0);
|
||||
}
|
||||
|
||||
/// HANDLERS
|
||||
|
||||
int BuilderHandler_MainMenu(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[32];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
if(StrEqual(info, "new")) {
|
||||
JSONObject temp = LoadMapJson(currentMap);
|
||||
GetCmdArg(2, info, sizeof(info));
|
||||
if(temp != null) {
|
||||
Menu nMenu = new Menu(BuilderHandler_MainMenu);
|
||||
nMenu.SetTitle("Existing map data exists");
|
||||
nMenu.AddItem("new_confirm", "Overwrite");
|
||||
nMenu.Display(client, 0);
|
||||
delete temp;
|
||||
return 0;
|
||||
} else {
|
||||
FakeClientCommand(client, "sm_rbuild new");
|
||||
}
|
||||
} else if(StrEqual(info, "new_confirm")) {
|
||||
FakeClientCommand(client, "sm_rbuild new confirm");
|
||||
} else if(StrEqual(info, "scenes")) {
|
||||
OpenScenesMenu(client);
|
||||
return 0;
|
||||
} else {
|
||||
FakeClientCommand(client, "sm_rbuild %s", info);
|
||||
} /*else if(StrEqual(info, "cursor")) {
|
||||
Menu menu = new Menu(BuilderHandler_)
|
||||
}*/
|
||||
OpenMainMenu(client);
|
||||
} else if(action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
}
|
||||
} else if (action == MenuAction_End) {
|
||||
delete menu;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BuilderHandler_ScenesMenu(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[64];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
if(StrEqual(info, "new")) {
|
||||
FakeClientCommand(client, "sm_rbuild scenes new");
|
||||
OpenScenesMenu(client);
|
||||
} else {
|
||||
FakeClientCommand(client, "sm_rbuild scenes select %s", info);
|
||||
OpenVariantsMenu(client);
|
||||
}
|
||||
} else if(action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
}
|
||||
} else if (action == MenuAction_End) {
|
||||
delete menu;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BuilderHandler_VariantsMenu(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[64];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
if(StrEqual(info, "new")) {
|
||||
FakeClientCommand(client, "sm_rbuild scenes variants new");
|
||||
} else {
|
||||
FakeClientCommand(client, "sm_rbuild scenes variants select %s", info);
|
||||
}
|
||||
OpenVariantsMenu(client);
|
||||
} else if(action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
}
|
||||
} else if (action == MenuAction_End) {
|
||||
delete menu;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -249,8 +249,8 @@ void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast)
|
|||
CPrintChatToAdmins("{olive}%N{default} has been banned for %d minutes (marked as troll). If this was a mistake, you can discard their ban from the admin panel at {yellow}https://admin.jackz.me", client, hBanTime.IntValue);
|
||||
else
|
||||
CPrintChatToAdmins("{olive}%N{default} has been permanently banned (marked as troll). If this was a mistake, you can discard their ban from the admin panel at {yellow}https://admin.jackz.me", client);
|
||||
pData[client].isTroll = false;
|
||||
}
|
||||
pData[client].isTroll = false;
|
||||
|
||||
if(!IsFakeClient(client)) {
|
||||
float minutesSinceiLastFFTime = GetLastFFMinutes(client);
|
||||
|
|
|
@ -90,7 +90,7 @@ ConVar cvEPICommonCountScale, cvEPICommonCountScaleMax;
|
|||
ConVar g_ffFactorCvar, hExtraTankThreshold;
|
||||
|
||||
|
||||
ConVar cvZCommonLimit; int zCommonLimitPrevValue;
|
||||
ConVar cvZCommonLimit; int commonLimitBase; bool isSettingLimit;
|
||||
|
||||
int g_extraKitsAmount, g_extraKitsStart, g_saferoomDoorEnt, g_prevPlayerCount;
|
||||
bool g_forcedSurvivorCount, g_extraKitsSpawnedFinale;
|
||||
|
@ -326,6 +326,10 @@ public void OnPluginStart() {
|
|||
cvEPICommonCountScaleMax = CreateConVar("epi_commons_scale_max", "60", "The maximum amount that z_common_limit can be scaled to.", FCVAR_NONE, true, 0.0);
|
||||
cvZCommonLimit = FindConVar("z_common_limit");
|
||||
|
||||
cvEPICommonCountScale.AddChangeHook(Cvar_CommonScaleChange);
|
||||
cvEPICommonCountScaleMax.AddChangeHook(Cvar_CommonScaleChange);
|
||||
cvZCommonLimit.AddChangeHook(Cvar_CommonScaleChange);
|
||||
|
||||
// TODO: hook flags, reset name index / ping mode
|
||||
cvEPIHudFlags.AddChangeHook(Cvar_HudStateChange);
|
||||
cvEPISpecialSpawning.AddChangeHook(Cvar_SpecialSpawningChange);
|
||||
|
@ -428,6 +432,7 @@ public void OnPluginEnd() {
|
|||
delete weaponMaxClipSizes;
|
||||
delete g_ammoPacks;
|
||||
L4D2_ExecVScriptCode(HUD_SCRIPT_CLEAR);
|
||||
_UnsetCommonLimit();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -482,6 +487,19 @@ void Cvar_HudStateChange(ConVar convar, const char[] oldValue, const char[] newV
|
|||
TryStartHud();
|
||||
}
|
||||
}
|
||||
void Cvar_CommonScaleChange(ConVar convar, const char[] oldValue, const char[] newValue) {
|
||||
if(convar == cvZCommonLimit) {
|
||||
PrintToServer("z_common_limit changed [value=%d] [isSettingLimit=%b]", convar.IntValue, isSettingLimit);
|
||||
// Ignore our own changes:
|
||||
if(isSettingLimit) {
|
||||
isSettingLimit = false;
|
||||
return;
|
||||
}
|
||||
commonLimitBase = convar.IntValue;
|
||||
}
|
||||
_SetCommonLimit();
|
||||
|
||||
}
|
||||
void TryStartHud() {
|
||||
int threshold = 0;
|
||||
// Default to 0 for state == 2 (force)
|
||||
|
@ -572,6 +590,7 @@ Action Command_EpiVal(int client, int args) {
|
|||
PrintToConsole(client, "restCount = %d", g_restCount);
|
||||
PrintToConsole(client, "extraFinaleTankEnabled = %b", g_extraFinaleTankEnabled);
|
||||
PrintToConsole(client, "g_areItemsPopulated = %b", g_areItemsPopulated);
|
||||
PrintToConsole(client, "commonLimitBase = %d", commonLimitBase);
|
||||
ReplyToCommand(client, "Values printed to console");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
@ -1343,7 +1362,7 @@ public void OnMapStart() {
|
|||
if(L4D_IsMissionFinalMap()) {
|
||||
// Disable tank split on hard rain finale
|
||||
g_extraFinaleTankEnabled = true;
|
||||
if(StrEqual(map, "c4m5_milltown_escape")) {
|
||||
if(StrEqual(map, "c4m5_milltown_escape") || StrEqual(map, "c14m2_lighthouse")) {
|
||||
g_extraFinaleTankEnabled = false;
|
||||
}
|
||||
}
|
||||
|
@ -1454,6 +1473,7 @@ public void OnConfigsExecuted() {
|
|||
if(hUpdateMinPlayers.BoolValue && hMinPlayers != null) {
|
||||
hMinPlayers.IntValue = g_realSurvivorCount;
|
||||
}
|
||||
_SetCommonLimit();
|
||||
}
|
||||
|
||||
public void OnMapEnd() {
|
||||
|
@ -2102,28 +2122,41 @@ void UpdateSurvivorCount() {
|
|||
} else if(wasActive) {
|
||||
OnEPIInactive();
|
||||
}
|
||||
|
||||
if(isActive)
|
||||
if(isActive) {
|
||||
SetFFFactor(g_epiEnabled);
|
||||
_SetCommonLimit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OnEPIActive() {
|
||||
zCommonLimitPrevValue = cvZCommonLimit.IntValue;
|
||||
_SetCommonLimit();
|
||||
}
|
||||
|
||||
void OnEPIInactive() {
|
||||
_UnsetCommonLimit();
|
||||
}
|
||||
|
||||
void _UnsetCommonLimit() {
|
||||
if(commonLimitBase > 0) {
|
||||
cvZCommonLimit.IntValue = commonLimitBase;
|
||||
}
|
||||
commonLimitBase = 0;
|
||||
}
|
||||
void _SetCommonLimit() {
|
||||
if(!g_epiEnabled || commonLimitBase <= 0) return;
|
||||
// TODO: lag check for common limit
|
||||
if(cvEPICommonCountScale.IntValue > 0) {
|
||||
int newLimit = zCommonLimitPrevValue + RoundFloat(cvEPICommonCountScale.FloatValue * float(g_realSurvivorCount));
|
||||
if(cvEPICommonCountScale.IntValue > 0 && commonLimitBase > 0) {
|
||||
int newLimit = commonLimitBase + RoundFloat(cvEPICommonCountScale.FloatValue * float(g_realSurvivorCount - 4));
|
||||
PrintDebug(DEBUG_INFO, "Setting common scale: %d + (%f * %d) [max=%d] = %d", commonLimitBase, cvEPICommonCountScale.FloatValue, g_realSurvivorCount - 4, cvEPICommonCountScaleMax.IntValue, newLimit);
|
||||
if(newLimit > 0) {
|
||||
if(newLimit > cvEPICommonCountScaleMax.IntValue) {
|
||||
newLimit = cvEPICommonCountScaleMax.IntValue;
|
||||
}
|
||||
}
|
||||
isSettingLimit = true;
|
||||
cvZCommonLimit.IntValue = newLimit;
|
||||
}
|
||||
}
|
||||
|
||||
void OnEPIInactive() {
|
||||
cvZCommonLimit.IntValue = zCommonLimitPrevValue;
|
||||
}
|
||||
}
|
||||
void SetFFFactor(bool enabled) {
|
||||
static float prevValue;
|
||||
|
|
|
@ -213,6 +213,7 @@ public void Event_GamemodeChange(ConVar cvar, const char[] oldValue, const char[
|
|||
HookEvent("player_bot_replace", Event_PlayerToBot);
|
||||
HookEvent("player_ledge_grab", Event_LedgeGrab);
|
||||
AddCommandListener(OnGoAwayFromKeyboard, "go_away_from_keyboard");
|
||||
InitGamemode();
|
||||
} else if(!lateLoaded) {
|
||||
cvarStorage.Restore();
|
||||
delete cvarStorage;
|
||||
|
@ -462,7 +463,8 @@ Action Timer_SpawnBots(Handle h, int max) {
|
|||
if(AddSurvivor()) {
|
||||
count++;
|
||||
return Plugin_Continue;
|
||||
} else {
|
||||
} else if(count < 0) {
|
||||
// Fail if we couldnt make enough bots
|
||||
PrintToChatAll("GUESS WHO: FATAL ERROR: AddSurvivor() failed");
|
||||
LogError("Guess Who: Fatal Error: AddSurvivor() failed");
|
||||
count = 0;
|
||||
|
@ -561,6 +563,7 @@ Action Timer_WaitForStart(Handle h) {
|
|||
Game.State = State_Starting;
|
||||
Game.Tick = 0;
|
||||
Game.MapTime = RoundFloat(seedTime);
|
||||
Game.PopulateCoins();
|
||||
CreateTimer(seedTime, Timer_StartSeeker);
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
@ -585,6 +588,7 @@ Action Timer_StartSeeker(Handle h) {
|
|||
Action Timer_TimesUp(Handle h) {
|
||||
Game.Broadcast("The seeker ran out of time. Hiders win!");
|
||||
Game.End(State_HidersWin);
|
||||
timesUpTimer = null;
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ char g_currentMap[64];
|
|||
#include <hats/hats.sp>
|
||||
#include <hats/hat_presets.sp>
|
||||
#include <hats/props/base.sp>
|
||||
#include <hats/natives.sp>
|
||||
#include <hats_editor>
|
||||
|
||||
public Plugin myinfo = {
|
||||
name = "L4D2 Hats & Editor",
|
||||
|
@ -56,6 +58,32 @@ public Plugin myinfo = {
|
|||
};
|
||||
|
||||
ArrayList NavAreas;
|
||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) {
|
||||
RegPluginLibrary("editor");
|
||||
// CreateNative("SpawnSchematic", Native_SpawnSchematic);
|
||||
CreateNative("StartEdit", Native_StartEdit);
|
||||
CreateNative("StartSpawner", Native_StartSpawner);
|
||||
CreateNative("CancelEdit", Native_CancelEdit);
|
||||
CreateNative("IsEditorActive", Native_IsEditorActive);
|
||||
|
||||
|
||||
CreateNative("StartSelector", Native_StartSelector);
|
||||
CreateNative("CancelSelector", Native_CancelSelector);
|
||||
CreateNative("IsSelectorActive", Native_IsSelectorActive);
|
||||
|
||||
CreateNative("EntitySelector.Start", Native_Selector_Start);
|
||||
CreateNative("EntitySelector.Count.get", Native_Selector_GetCount);
|
||||
CreateNative("EntitySelector.Active.get", Native_Selector_GetActive);
|
||||
CreateNative("EntitySelector.SetOnEnd", Native_Selector_SetOnEnd);
|
||||
CreateNative("EntitySelector.SetOnPreSelect", Native_Selector_SetOnPreSelect);
|
||||
CreateNative("EntitySelector.SetOnPostSelect", Native_Selector_SetOnPostSelect);
|
||||
CreateNative("EntitySelector.SetOnUnselect", Native_Selector_SetOnUnselect);
|
||||
CreateNative("EntitySelector.AddEntity", Native_Selector_AddEntity);
|
||||
CreateNative("EntitySelector.RemoveEntity", Native_Selector_RemoveEntity);
|
||||
CreateNative("EntitySelector.Cancel", Native_Selector_Cancel);
|
||||
CreateNative("EntitySelector.End", Native_Selector_End);
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
|
||||
public void OnPluginStart() {
|
||||
|
@ -116,6 +144,7 @@ public void OnPluginStart() {
|
|||
for(int i = 1; i <= MaxClients; i++) {
|
||||
Editor[i].client = i;
|
||||
Editor[i].Reset(true);
|
||||
g_PropData[i].Init(i);
|
||||
hatData[i].yeetGroundTimer = null;
|
||||
}
|
||||
|
||||
|
@ -456,6 +485,7 @@ ArrayList GetSpawnLocations() {
|
|||
return newList;
|
||||
}
|
||||
|
||||
|
||||
void ChooseRandomPosition(float pos[3], int ignoreClient = 0) {
|
||||
if(NavAreas.Length > 0 && GetURandomFloat() > 0.5) {
|
||||
int nav = NavAreas.Get(GetURandomInt() % (NavAreas.Length - 1));
|
||||
|
@ -578,34 +608,34 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
if(g_PropData[client].pendingSaveType == Save_Schematic) {
|
||||
// move cursor? or should be editor anyway
|
||||
}
|
||||
} else if(g_PropData[client].markedProps != null) {
|
||||
} else if(g_PropData[client].Selector.IsActive()) {
|
||||
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);
|
||||
if(g_PropData[client].Selector.AddEntity(entity) != -1) {
|
||||
PrecacheSound("ui/beep07.wav");
|
||||
EmitSoundToClient(client, "ui/beep07.wav", entity, SND_CHANGEVOL, .volume = 0.5);
|
||||
}
|
||||
} 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);
|
||||
if(g_PropData[client].Selector.RemoveEntity(entity)) {
|
||||
PrecacheSound("ui/beep22.wav");
|
||||
EmitSoundToClient(client, "ui/beep22.wav", entity, SND_CHANGEVOL, .volume = 0.5);
|
||||
}
|
||||
}
|
||||
} else if(buttons & IN_USE) {
|
||||
if(buttons & IN_SPEED) {
|
||||
//Delete
|
||||
EndDeleteTool(client, true);
|
||||
g_PropData[client].Selector.End();
|
||||
} else if(buttons & IN_DUCK) {
|
||||
//Cancel
|
||||
EndDeleteTool(client, false);
|
||||
g_PropData[client].Selector.Cancel();
|
||||
}
|
||||
}
|
||||
cmdThrottle[client] = tick;
|
||||
|
@ -628,31 +658,37 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
}
|
||||
if(!(oldButtons & IN_JUMP) && (buttons & IN_JUMP)) {
|
||||
buttons &= ~IN_JUMP;
|
||||
Editor[client].CycleStacker(tick);
|
||||
Editor[client].CycleStacker();
|
||||
} else if(!(oldButtons & IN_SPEED) && (buttons & IN_SPEED)) {
|
||||
Editor[client].ToggleCollision(tick);
|
||||
Editor[client].ToggleCollision();
|
||||
return Plugin_Handled;
|
||||
} else if(!(oldButtons & IN_DUCK) && (buttons & IN_DUCK)) {
|
||||
Editor[client].ToggleCollisionRotate(tick);
|
||||
Editor[client].ToggleCollisionRotate();
|
||||
return Plugin_Handled;
|
||||
} else {
|
||||
PrintCenterText(client, "%.1f %.1f %.1f", Editor[client].angles[0], Editor[client].angles[1], Editor[client].angles[2]);
|
||||
isRotate = true;
|
||||
SetEntityFlags(client, flags |= FL_FROZEN);
|
||||
if(!(oldButtons & IN_ATTACK) && (buttons & IN_ATTACK)) Editor[client].CycleAxis(tick);
|
||||
else if(buttons & IN_ATTACK2) Editor[client].CycleSnapAngle(tick);
|
||||
if(!(oldButtons & IN_ATTACK) && (buttons & IN_ATTACK)) Editor[client].CycleAxis();
|
||||
else if(!(oldButtons & IN_ATTACK2) && (buttons & IN_ATTACK2)) Editor[client].CycleSnapAngle(tick);
|
||||
|
||||
// Rotation control:
|
||||
// Turn off rotate when player wants rotate
|
||||
Editor[client].hasCollisionRotate = false;
|
||||
if(tick - cmdThrottle[client] > 0.1) {
|
||||
if(Editor[client].axis == 2) {
|
||||
if(mouse[1] > 10) Editor[client].angles[2] += Editor[client].snapAngle;
|
||||
else if(mouse[1] < -10) Editor[client].angles[2] -= Editor[client].snapAngle;
|
||||
} else {
|
||||
if(mouse[0] > 10) Editor[client].angles[Editor[client].axis] += Editor[client].snapAngle;
|
||||
else if(mouse[0] < -10) Editor[client].angles[Editor[client].axis] -= Editor[client].snapAngle;
|
||||
|
||||
if(Editor[client].axis == 0) {
|
||||
int mouseXAbs = IntAbs(mouse[0]);
|
||||
int mouseYAbs = IntAbs(mouse[1]);
|
||||
bool XOverY = mouseXAbs > mouseYAbs;
|
||||
if(mouseYAbs > 10 && !XOverY) {
|
||||
Editor[client].IncrementAxis(0, mouse[1]);
|
||||
} else if(mouseXAbs > 10 && XOverY) {
|
||||
Editor[client].IncrementAxis(1, mouse[0]);
|
||||
}
|
||||
}
|
||||
else if(Editor[client].axis == 1) {
|
||||
if(mouse[0] > 10) Editor[client].angles[2] += Editor[client].snapAngle;
|
||||
else if(mouse[0] < -10) Editor[client].angles[2] -= Editor[client].snapAngle;
|
||||
}
|
||||
cmdThrottle[client] = tick;
|
||||
}
|
||||
|
@ -701,24 +737,27 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
}
|
||||
case COLOR: {
|
||||
SetWeaponDelay(client, 0.5);
|
||||
PrintCenterText(client, "%d %d %d %d", Editor[client].color[0], Editor[client].color[1], Editor[client].color[2], Editor[client].color[3]);
|
||||
PrintHintText(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) {
|
||||
Editor[client].CycleColorComponent(tick);
|
||||
} else if(buttons & IN_ATTACK) {
|
||||
} else if(buttons & IN_ATTACK2) {
|
||||
Editor[client].IncreaseColor(1);
|
||||
allowMove = false;
|
||||
} else if(buttons & IN_ATTACK2) {
|
||||
} else if(buttons & IN_ATTACK) {
|
||||
Editor[client].IncreaseColor(-1);
|
||||
allowMove = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!(oldButtons & IN_USE) && buttons & IN_USE) {
|
||||
if(buttons & IN_DUCK) {
|
||||
|
||||
}
|
||||
if(Editor[client].mode != COLOR && !(oldButtons & IN_USE) && buttons & IN_USE) {
|
||||
if(buttons & IN_SPEED) {
|
||||
Editor[client].Cancel();
|
||||
} else if(buttons & IN_DUCK) {
|
||||
if(Editor[client].flags & Edit_Preview)
|
||||
Editor[client].CycleBuildType();
|
||||
// Editor[client].ShowExtraOptions();
|
||||
} else {
|
||||
int entity;
|
||||
Editor[client].Done(entity);
|
||||
|
@ -735,6 +774,12 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
int IntAbs(int a) {
|
||||
if(a < 0) {
|
||||
return a * -1;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
// Don't show real entity to hat wearer (Show for ALL but hat wearer)
|
||||
Action OnRealTransmit(int entity, int client) {
|
||||
|
@ -914,6 +959,7 @@ bool Filter_ValidHats(int entity, int mask, int data) {
|
|||
}
|
||||
|
||||
bool CheckBlacklist(int entity) {
|
||||
if(entity == 0) return false;
|
||||
if(cvar_sm_hats_blacklist_enabled.BoolValue) {
|
||||
static char buffer[64];
|
||||
GetEntityClassname(entity, buffer, sizeof(buffer));
|
||||
|
|
|
@ -11,9 +11,12 @@
|
|||
#include <sdktools>
|
||||
//#include <sdkhooks>
|
||||
#include <profiler>
|
||||
#include <json>
|
||||
// #include <json>
|
||||
#include <ripext>
|
||||
#include <jutils>
|
||||
#include <entitylump>
|
||||
#undef REQUIRE_PLUGIN
|
||||
#include <hats_editor>
|
||||
|
||||
int g_iLaserIndex;
|
||||
#if defined DEBUG_BLOCKERS
|
||||
|
@ -27,6 +30,77 @@ int g_iLaserIndex;
|
|||
#define MAX_SCENE_NAME_LENGTH 32
|
||||
#define MAX_INPUTS_CLASSNAME_LENGTH 64
|
||||
|
||||
|
||||
ConVar cvarEnabled;
|
||||
enum struct ActiveSceneData {
|
||||
char name[MAX_SCENE_NAME_LENGTH];
|
||||
int variantIndex;
|
||||
}
|
||||
MapData g_MapData;
|
||||
BuilderData g_builder;
|
||||
char currentMap[64];
|
||||
|
||||
enum struct BuilderData {
|
||||
JSONObject mapData;
|
||||
|
||||
JSONObject selectedSceneData;
|
||||
char selectedSceneId[64];
|
||||
|
||||
JSONObject selectedVariantData;
|
||||
int selectedVariantIndex;
|
||||
|
||||
void Cleanup() {
|
||||
this.selectedSceneData = null;
|
||||
this.selectedVariantData = null;
|
||||
this.selectedVariantIndex = -1;
|
||||
this.selectedSceneId[0] = '\0';
|
||||
if(this.mapData != null)
|
||||
delete this.mapData;
|
||||
// JSONcleanup_and_delete(this.mapData);
|
||||
}
|
||||
|
||||
bool SelectScene(const char[] group) {
|
||||
if(!g_builder.mapData.HasKey(group)) return false;
|
||||
this.selectedSceneData = view_as<JSONObject>(g_builder.mapData.Get(group));
|
||||
strcopy(this.selectedSceneId, sizeof(this.selectedSceneId), group);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a variant, enter -1 to not select any (scene's entities)
|
||||
*/
|
||||
bool SelectVariant(int index = -1) {
|
||||
if(this.selectedSceneData == null) LogError("SelectVariant called, but no group selected");
|
||||
JSONArray variants = view_as<JSONArray>(this.selectedSceneData.Get("variants"));
|
||||
if(index >= variants.Length) return false;
|
||||
else if(index < -1) return false;
|
||||
else if(index > -1) {
|
||||
this.selectedVariantData = view_as<JSONObject>(variants.Get(index));
|
||||
} else {
|
||||
this.selectedVariantData = null;
|
||||
}
|
||||
this.selectedVariantIndex = index;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddEntity(int entity, ExportType exportType = Export_Model) {
|
||||
JSONArray entities;
|
||||
if(g_builder.selectedVariantData == null) {
|
||||
// Create <scene>.entities if doesn't exist:
|
||||
if(!g_builder.selectedSceneData.HasKey("entities")) {
|
||||
g_builder.selectedSceneData.Set("entities", new JSONArray());
|
||||
}
|
||||
entities = view_as<JSONArray>(g_builder.selectedSceneData.Get("entities"));
|
||||
} else {
|
||||
entities = view_as<JSONArray>(g_builder.selectedVariantData.Get("entities"));
|
||||
}
|
||||
JSONObject entityData = ExportEntity(entity, Export_Model);
|
||||
entities.Push(entityData);
|
||||
}
|
||||
}
|
||||
|
||||
#include <randomizer/rbuild.sp>
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "L4D2 Randomizer",
|
||||
|
@ -36,13 +110,6 @@ public Plugin myinfo =
|
|||
url = "https://github.com/Jackzmc/sourcemod-plugins"
|
||||
};
|
||||
|
||||
ConVar cvarEnabled;
|
||||
enum struct ActiveSceneData {
|
||||
char name[MAX_SCENE_NAME_LENGTH];
|
||||
int variantIndex;
|
||||
}
|
||||
MapData g_MapData;
|
||||
|
||||
public void OnPluginStart() {
|
||||
EngineVersion g_Game = GetEngineVersion();
|
||||
if(g_Game != Engine_Left4Dead && g_Game != Engine_Left4Dead2) {
|
||||
|
@ -51,15 +118,14 @@ public void OnPluginStart() {
|
|||
|
||||
RegAdminCmd("sm_rcycle", Command_CycleRandom, ADMFLAG_CHEATS);
|
||||
RegAdminCmd("sm_expent", Command_ExportEnt, ADMFLAG_GENERIC);
|
||||
RegAdminCmd("sm_rbuild", Command_RandomizerBuild, ADMFLAG_CHEATS);
|
||||
|
||||
cvarEnabled = CreateConVar("sm_randomizer_enabled", "0");
|
||||
|
||||
g_MapData.activeScenes = new ArrayList(sizeof(ActiveSceneData));
|
||||
}
|
||||
|
||||
char currentMap[64];
|
||||
|
||||
bool hasRan;
|
||||
// TODO: on round start
|
||||
public void OnMapStart() {
|
||||
g_iLaserIndex = PrecacheModel("materials/sprites/laserbeam.vmt", true);
|
||||
|
@ -69,6 +135,7 @@ public void OnMapStart() {
|
|||
}
|
||||
|
||||
public void OnMapEnd() {
|
||||
g_builder.Cleanup();
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
|
@ -124,9 +191,7 @@ public Action Command_CycleRandom(int client, int args) {
|
|||
if(args > 0) {
|
||||
DeleteCustomEnts();
|
||||
|
||||
char arg1[8];
|
||||
GetCmdArg(1, arg1, sizeof(arg1));
|
||||
int flags = StringToInt(arg1) | view_as<int>(FLAG_REFRESH);
|
||||
int flags = GetCmdArgInt(1) | view_as<int>(FLAG_REFRESH);
|
||||
RunMap(currentMap, flags);
|
||||
if(client > 0)
|
||||
PrintCenterText(client, "Cycled flags=%d", flags);
|
||||
|
@ -141,7 +206,7 @@ public Action Command_CycleRandom(int client, int args) {
|
|||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action Command_ExportEnt(int client, int args) {
|
||||
Action Command_ExportEnt(int client, int args) {
|
||||
float origin[3];
|
||||
int entity = GetLookingPosition(client, Filter_IgnorePlayer, origin);
|
||||
float angles[3];
|
||||
|
@ -188,6 +253,271 @@ public Action Command_ExportEnt(int client, int args) {
|
|||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
Action Command_RandomizerBuild(int client, int args) {
|
||||
char arg[64];
|
||||
GetCmdArg(1, arg, sizeof(arg));
|
||||
if(StrEqual(arg, "new")) {
|
||||
JSONObject temp = LoadMapJson(currentMap);
|
||||
GetCmdArg(2, arg, sizeof(arg));
|
||||
if(temp != null && !StrEqual(arg, "confirm")) {
|
||||
delete temp;
|
||||
ReplyToCommand(client, "Existing map data found, enter /rbuild new confirm to overwrite.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
g_builder.Cleanup();
|
||||
g_builder.mapData = new JSONObject();
|
||||
SaveMapJson(currentMap, g_builder.mapData);
|
||||
ReplyToCommand(client, "Started new map data for %s", currentMap);
|
||||
} else if(StrEqual(arg, "load")) {
|
||||
if(args >= 2) {
|
||||
GetCmdArg(2, arg, sizeof(arg));
|
||||
} else {
|
||||
strcopy(arg, sizeof(arg), currentMap);
|
||||
}
|
||||
g_builder.Cleanup();
|
||||
g_builder.mapData = LoadMapJson(arg);
|
||||
if(g_builder.mapData != null) {
|
||||
ReplyToCommand(client, "Loaded map data for %s", arg);
|
||||
} else {
|
||||
ReplyToCommand(client, "No map data found for %s", arg);
|
||||
}
|
||||
} else if(StrEqual(arg, "menu")) {
|
||||
OpenMainMenu(client);
|
||||
} else if(g_builder.mapData == null) {
|
||||
ReplyToCommand(client, "No map data for %s, either load with /rbuild load, or start new /rbuild new", currentMap);
|
||||
return Plugin_Handled;
|
||||
} else if(StrEqual(arg, "save")) {
|
||||
SaveMapJson(currentMap, g_builder.mapData);
|
||||
ReplyToCommand(client, "Saved %s", currentMap);
|
||||
} else if(StrEqual(arg, "scenes")) {
|
||||
Command_RandomizerBuild_Scenes(client, args);
|
||||
} else if(StrEqual(arg, "sel") || StrEqual(arg, "selector")) {
|
||||
if(g_builder.selectedVariantData == null) {
|
||||
ReplyToCommand(client, "Please load map data, select a scene and a variant.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
StartSelector(client, OnSelectorDone);
|
||||
} else if(StrEqual(arg, "spawner")) {
|
||||
if(g_builder.selectedVariantData == null) {
|
||||
ReplyToCommand(client, "Please load map data, select a scene and a variant.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
StartSpawner(client, OnSpawnerDone);
|
||||
ReplyToCommand(client, "Spawn props to add to variant");
|
||||
} else if(StrEqual(arg, "cursor")) {
|
||||
if(g_builder.selectedVariantData == null) {
|
||||
ReplyToCommand(client, "Please load map data, select a scene and a variant.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
float origin[3];
|
||||
char arg1[32];
|
||||
int entity = GetLookingPosition(client, Filter_IgnorePlayer, origin);
|
||||
GetCmdArg(2, arg1, sizeof(arg1));
|
||||
ExportType exportType = Export_Model;
|
||||
if(StrEqual(arg1, "hammerid")) {
|
||||
exportType = Export_HammerId;
|
||||
} else if(StrEqual(arg1, "targetname")) {
|
||||
exportType = Export_TargetName;
|
||||
}
|
||||
if(entity > 0) {
|
||||
g_builder.AddEntity(entity, exportType);
|
||||
ReplyToCommand(client, "Added entity #%d to variant #%d", entity, g_builder.selectedVariantIndex);
|
||||
} else {
|
||||
ReplyToCommand(client, "No entity found");
|
||||
}
|
||||
} else if(StrEqual(arg, "entityid")) {
|
||||
char arg1[32];
|
||||
int entity = GetCmdArgInt(2);
|
||||
GetCmdArg(3, arg1, sizeof(arg));
|
||||
ExportType exportType = Export_Model;
|
||||
if(StrEqual(arg1, "hammerid")) {
|
||||
exportType = Export_HammerId;
|
||||
} else if(StrEqual(arg1, "targetname")) {
|
||||
exportType = Export_TargetName;
|
||||
}
|
||||
if(entity > 0) {
|
||||
g_builder.AddEntity(entity, exportType);
|
||||
ReplyToCommand(client, "Added entity #%d to variant #%d", entity, g_builder.selectedVariantIndex);
|
||||
} else {
|
||||
ReplyToCommand(client, "No entity found");
|
||||
}
|
||||
} else {
|
||||
ReplyToCommand(client, "Unknown arg. Try: new, load, save, scenes, cursor");
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
enum ExportType {
|
||||
Export_HammerId,
|
||||
Export_TargetName,
|
||||
Export_Model
|
||||
}
|
||||
JSONObject ExportEntity(int entity, ExportType exportType = Export_Model) {
|
||||
float origin[3], angles[3], size[3];
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", origin);
|
||||
GetEntPropVector(entity, Prop_Send, "m_angRotation", angles);
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", size);
|
||||
|
||||
char model[64];
|
||||
JSONObject entityData = new JSONObject();
|
||||
GetEntityClassname(entity, model, sizeof(model));
|
||||
if(StrContains(model, "prop_") == -1) {
|
||||
entityData.Set("scale", VecToArray(size));
|
||||
}
|
||||
if(exportType == Export_HammerId) {
|
||||
int hammerid = GetEntProp(entity, Prop_Data, "m_iHammerID");
|
||||
entityData.SetString("type", "hammerid");
|
||||
char id[16];
|
||||
IntToString(hammerid, id, sizeof(id));
|
||||
entityData.SetString("model", id);
|
||||
} else if(exportType == Export_TargetName) {
|
||||
GetEntPropString(entity, Prop_Data, "m_iName", model, sizeof(model));
|
||||
entityData.SetString("type", "targetname");
|
||||
entityData.SetString("model", model);
|
||||
} else {
|
||||
GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||
entityData.SetString("model", model);
|
||||
}
|
||||
entityData.Set("origin", VecToArray(origin));
|
||||
entityData.Set("angles", VecToArray(angles));
|
||||
return entityData;
|
||||
}
|
||||
|
||||
bool OnSpawnerDone(int client, int entity, CompleteType result) {
|
||||
PrintToServer("Randomizer OnSpawnerDone");
|
||||
if(result == Complete_PropSpawned && entity > 0) {
|
||||
JSONObject entityData = ExportEntity(entity, Export_Model);
|
||||
JSONArray entities = view_as<JSONArray>(g_builder.selectedVariantData.Get("entities"));
|
||||
entities.Push(entityData);
|
||||
ReplyToCommand(client, "Added entity to variant");
|
||||
RemoveEntity(entity);
|
||||
}
|
||||
return result == Complete_PropSpawned;
|
||||
}
|
||||
void OnSelectorDone(int client, ArrayList entities) {
|
||||
JSONArray entArray = view_as<JSONArray>(g_builder.selectedVariantData.Get("entities"));
|
||||
if(entities != null) {
|
||||
JSONObject entityData;
|
||||
for(int i = 0; i < entities.Length; i++) {
|
||||
int ref = entities.Get(i);
|
||||
entityData = ExportEntity(ref, Export_Model);
|
||||
entArray.Push(entityData);
|
||||
delete entityData; //?
|
||||
RemoveEntity(ref);
|
||||
}
|
||||
PrintToChat(client, "Added %d entities to variant", entities.Length);
|
||||
delete entities;
|
||||
}
|
||||
}
|
||||
|
||||
JSONArray VecToArray(float vec[3]) {
|
||||
JSONArray arr = new JSONArray();
|
||||
arr.PushFloat(vec[0]);
|
||||
arr.PushFloat(vec[1]);
|
||||
arr.PushFloat(vec[2]);
|
||||
return arr;
|
||||
}
|
||||
|
||||
void Command_RandomizerBuild_Scenes(int client, int args) {
|
||||
char arg[16];
|
||||
GetCmdArg(2, arg, sizeof(arg));
|
||||
if(StrEqual(arg, "new")) {
|
||||
if(args < 4) {
|
||||
ReplyToCommand(client, "Syntax: /rbuild scenes new <name> <chance 0.0-1.0>");
|
||||
} else {
|
||||
char name[64];
|
||||
GetCmdArg(3, name, sizeof(name));
|
||||
GetCmdArg(4, arg, sizeof(arg));
|
||||
float chance = StringToFloat(arg);
|
||||
JSONObject scene = new JSONObject();
|
||||
scene.SetFloat("chance", chance);
|
||||
scene.Set("variants", new JSONArray());
|
||||
g_builder.mapData.Set(name, scene);
|
||||
g_builder.SelectScene(name);
|
||||
JSONArray variants = view_as<JSONArray>(g_builder.selectedSceneData.Get("variants"));
|
||||
|
||||
JSONObject variantObj = new JSONObject();
|
||||
variantObj.SetInt("weight", 1);
|
||||
variantObj.Set("entities", new JSONArray());
|
||||
variants.Push(variantObj);
|
||||
g_builder.SelectVariant(0);
|
||||
ReplyToCommand(client, "Created & selected scene & variant %s#0", name);
|
||||
StartSelector(client, OnSelectorDone);
|
||||
}
|
||||
} else if(StrEqual(arg, "select") || StrEqual(arg, "load") || StrEqual(arg, "choose")) {
|
||||
GetCmdArg(3, arg, sizeof(arg));
|
||||
if(g_builder.SelectScene(arg)) {
|
||||
int variantIndex;
|
||||
if(GetCmdArgIntEx(4, variantIndex)) {
|
||||
if(g_builder.SelectVariant(variantIndex)) {
|
||||
ReplyToCommand(client, "Selected scene: %s#%d", arg, variantIndex);
|
||||
} else {
|
||||
ReplyToCommand(client, "Unknown variant for scene");
|
||||
}
|
||||
} else {
|
||||
ReplyToCommand(client, "Selected scene: %s", arg);
|
||||
}
|
||||
} else {
|
||||
ReplyToCommand(client, "No scene found");
|
||||
}
|
||||
} else if(StrEqual(arg, "variants")) {
|
||||
Command_RandomizerBuild_Variants(client, args);
|
||||
} else if(args > 1) {
|
||||
ReplyToCommand(client, "Unknown argument, try: new, select, variants");
|
||||
} else {
|
||||
ReplyToCommand(client, "Scenes:");
|
||||
JSONObjectKeys iterator = g_builder.mapData.Keys();
|
||||
while(iterator.ReadKey(arg, sizeof(arg))) {
|
||||
if(StrEqual(arg, g_builder.selectedSceneId)) {
|
||||
ReplyToCommand(client, "\t%s (selected)", arg);
|
||||
} else {
|
||||
ReplyToCommand(client, "\t%s", arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Command_RandomizerBuild_Variants(int client, int args) {
|
||||
if(g_builder.selectedSceneId[0] == '\0') {
|
||||
ReplyToCommand(client, "No scene selected, select with /rbuild groups select <group>");
|
||||
return;
|
||||
}
|
||||
char arg[16];
|
||||
GetCmdArg(3, arg, sizeof(arg));
|
||||
if(StrEqual(arg, "new")) {
|
||||
// /rbuild group variants new [weight]
|
||||
int weight;
|
||||
if(!GetCmdArgIntEx(4, weight)) {
|
||||
weight = 1;
|
||||
}
|
||||
JSONArray variants = view_as<JSONArray>(g_builder.selectedSceneData.Get("variants"));
|
||||
JSONObject variantObj = new JSONObject();
|
||||
variantObj.SetInt("weight", weight);
|
||||
variantObj.Set("entities", new JSONArray());
|
||||
int index = variants.Push(variantObj);
|
||||
g_builder.SelectVariant(index);
|
||||
ReplyToCommand(client, "Created variant #%d", index);
|
||||
} else if(StrEqual(arg, "select")) {
|
||||
int index = GetCmdArgInt(4);
|
||||
if(g_builder.SelectVariant(index)) {
|
||||
ReplyToCommand(client, "Selected variant: %s#%d", g_builder.selectedSceneId, index);
|
||||
} else {
|
||||
ReplyToCommand(client, "No variant found");
|
||||
}
|
||||
} else {
|
||||
ReplyToCommand(client, "Variants:");
|
||||
JSONObject variantObj;
|
||||
JSONArray variants = view_as<JSONArray>(g_builder.selectedSceneData.Get("variants"));
|
||||
for(int i = 0; i < variants.Length; i++) {
|
||||
variantObj = view_as<JSONObject>(variants.Get(i));
|
||||
int weight = 1;
|
||||
if(variantObj.HasKey("weight"))
|
||||
weight = variantObj.GetInt("weight");
|
||||
JSONArray entities = view_as<JSONArray>(variantObj.Get("entities"));
|
||||
ReplyToCommand(client, " #%d. [W:%d] [#E:%d]", i, weight, entities.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum struct SceneData {
|
||||
|
@ -211,10 +541,12 @@ enum struct SceneVariantData {
|
|||
int weight;
|
||||
ArrayList inputsList;
|
||||
ArrayList entities;
|
||||
ArrayList forcedScenes;
|
||||
|
||||
void Cleanup() {
|
||||
delete this.inputsList;
|
||||
delete this.entities;
|
||||
delete this.forcedScenes;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,6 +698,7 @@ enum struct LumpEditData {
|
|||
}
|
||||
|
||||
enum struct MapData {
|
||||
StringMap scenesKv;
|
||||
ArrayList scenes;
|
||||
ArrayList lumpEdits;
|
||||
ArrayList activeScenes;
|
||||
|
@ -376,30 +709,40 @@ enum loadFlags {
|
|||
FLAG_ALL_SCENES = 1, // Pick all scenes, no random chance
|
||||
FLAG_ALL_VARIANTS = 2, // Pick all variants (for debug purposes),
|
||||
FLAG_REFRESH = 4, // Load data bypassing cache
|
||||
FLAG_FORCE_ACTIVE = 8 // Similar to ALL_SCENES, bypasses % chance
|
||||
}
|
||||
|
||||
// Reads (mapname).json file and parses it
|
||||
public bool LoadMapData(const char[] map, int flags) {
|
||||
public JSONObject LoadMapJson(const char[] map) {
|
||||
Debug("Loading config for %s", map);
|
||||
char filePath[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, filePath, sizeof(filePath), "data/randomizer/%s.json", map);
|
||||
if(!FileExists(filePath)) {
|
||||
Log("[Randomizer] No map config file (data/randomizer/%s.json), not loading", map);
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
char buffer[65536];
|
||||
File file = OpenFile(filePath, "r");
|
||||
if(file == null) {
|
||||
LogError("Could not open map config file (data/randomizer/%s.json)", map);
|
||||
return false;
|
||||
}
|
||||
file.ReadString(buffer, sizeof(buffer));
|
||||
JSON_Object data = json_decode(buffer);
|
||||
JSONObject data = JSONObject.FromFile(filePath);
|
||||
if(data == null) {
|
||||
LogError("Could not parse map config file (data/randomizer/%s.json)", map);
|
||||
return null;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
public void SaveMapJson(const char[] map, JSONObject json) {
|
||||
Debug("Saving config for %s", map);
|
||||
char filePath[PLATFORM_MAX_PATH], filePathTemp[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, filePathTemp, sizeof(filePath), "data/randomizer/%s.json.tmp", map);
|
||||
BuildPath(Path_SM, filePath, sizeof(filePath), "data/randomizer/%s.json", map);
|
||||
|
||||
json.ToFile(filePathTemp, JSON_INDENT(4));
|
||||
RenameFile(filePath, filePathTemp);
|
||||
SetFilePermissions(filePath, FPERM_U_WRITE | FPERM_U_READ | FPERM_G_WRITE | FPERM_G_READ | FPERM_O_READ);
|
||||
}
|
||||
|
||||
public bool LoadMapData(const char[] map, int flags) {
|
||||
JSONObject data = LoadMapJson(map);
|
||||
if(data == null) {
|
||||
json_get_last_error(buffer, sizeof(buffer));
|
||||
LogError("Could not parse map config file (data/randomizer/%s.json): %s", map, buffer);
|
||||
delete file;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -407,51 +750,51 @@ public bool LoadMapData(const char[] map, int flags) {
|
|||
|
||||
Cleanup();
|
||||
g_MapData.scenes = new ArrayList(sizeof(SceneData));
|
||||
g_MapData.scenesKv = new StringMap();
|
||||
g_MapData.lumpEdits = new ArrayList(sizeof(LumpEditData));
|
||||
g_MapData.activeScenes.Clear();
|
||||
|
||||
Profiler profiler = new Profiler();
|
||||
profiler.Start();
|
||||
|
||||
int length = data.Length;
|
||||
JSONObjectKeys iterator = data.Keys();
|
||||
char key[32];
|
||||
for (int i = 0; i < length; i += 1) {
|
||||
data.GetKey(i, key, sizeof(key));
|
||||
|
||||
while(iterator.ReadKey(key, sizeof(key))) {
|
||||
if(key[0] == '_') {
|
||||
if(StrEqual(key, "_lumps")) {
|
||||
JSON_Array lumpsList = view_as<JSON_Array>(data.GetObject(key));
|
||||
JSONArray lumpsList = view_as<JSONArray>(data.Get(key));
|
||||
if(lumpsList != null) {
|
||||
for(int l = 0; l < lumpsList.Length; l++) {
|
||||
loadLumpData(g_MapData.lumpEdits, lumpsList.GetObject(l));
|
||||
loadLumpData(g_MapData.lumpEdits, view_as<JSONObject>(lumpsList.Get(l)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Debug("Unknown special entry \"%s\", skipping", key);
|
||||
}
|
||||
} else {
|
||||
if(data.GetType(key) != JSON_Type_Object) {
|
||||
Debug("Invalid normal entry \"%s\" (not an object), skipping", key);
|
||||
continue;
|
||||
}
|
||||
JSON_Object scene = data.GetObject(key);
|
||||
// if(data.GetType(key) != JSONType_Object) {
|
||||
// Debug("Invalid normal entry \"%s\" (not an object), skipping", key);
|
||||
// continue;
|
||||
// }
|
||||
JSONObject scene = view_as<JSONObject>(data.Get(key));
|
||||
// Parses scene data and inserts to scenes
|
||||
loadScene(key, scene);
|
||||
}
|
||||
}
|
||||
|
||||
json_cleanup_and_delete(data);
|
||||
delete data;
|
||||
profiler.Stop();
|
||||
Log("Parsed map file for %s(%d) and found %d scenes in %.4f seconds", map, flags, g_MapData.scenes.Length, profiler.Time);
|
||||
delete profiler;
|
||||
delete file;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calls LoadMapData (read&parse (mapname).json) then select scenes
|
||||
public bool RunMap(const char[] map, int flags) {
|
||||
if(g_MapData.scenes == null || flags & view_as<int>(FLAG_REFRESH)) {
|
||||
LoadMapData(map, flags);
|
||||
if(!LoadMapData(map, flags)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Profiler profiler = new Profiler();
|
||||
|
||||
|
@ -463,7 +806,7 @@ public bool RunMap(const char[] map, int flags) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void loadScene(const char key[MAX_SCENE_NAME_LENGTH], JSON_Object sceneData) {
|
||||
void loadScene(const char key[MAX_SCENE_NAME_LENGTH], JSONObject sceneData) {
|
||||
SceneData scene;
|
||||
scene.name = key;
|
||||
scene.chance = sceneData.GetFloat("chance");
|
||||
|
@ -471,38 +814,73 @@ void loadScene(const char key[MAX_SCENE_NAME_LENGTH], JSON_Object sceneData) {
|
|||
LogError("Scene \"%s\" has invalid chance (%f)", scene.name, scene.chance);
|
||||
return;
|
||||
}
|
||||
// TODO: load "entities", merge with choice.entities
|
||||
sceneData.GetString("group", scene.group, sizeof(scene.group));
|
||||
scene.variants = new ArrayList(sizeof(SceneVariantData));
|
||||
JSON_Array variants = view_as<JSON_Array>(sceneData.GetObject("variants"));
|
||||
if(!sceneData.HasKey("variants")) {
|
||||
ThrowError("Failed to load: Scene \"%s\" has missing \"variants\" array", scene.name);
|
||||
return;
|
||||
}
|
||||
JSONArray entities;
|
||||
if(sceneData.HasKey("entities")) {
|
||||
entities = view_as<JSONArray>(sceneData.Get("entities"));
|
||||
}
|
||||
|
||||
JSONArray variants = view_as<JSONArray>(sceneData.Get("variants"));
|
||||
for(int i = 0; i < variants.Length; i++) {
|
||||
// Parses choice and loads to scene.choices
|
||||
loadChoice(scene, variants.GetObject(i));
|
||||
loadChoice(scene, view_as<JSONObject>(variants.Get(i)), entities);
|
||||
}
|
||||
g_MapData.scenes.PushArray(scene);
|
||||
g_MapData.scenesKv.SetArray(scene.name, scene, sizeof(scene));
|
||||
}
|
||||
|
||||
void loadChoice(SceneData scene, JSON_Object choiceData) {
|
||||
void loadChoice(SceneData scene, JSONObject choiceData, JSONArray extraEntities) {
|
||||
SceneVariantData choice;
|
||||
choice.weight = choiceData.GetInt("weight", 1);
|
||||
choice.weight = 1;
|
||||
if(choiceData.HasKey("weight"))
|
||||
choice.weight = choiceData.GetInt("weight");
|
||||
choice.entities = new ArrayList(sizeof(VariantEntityData));
|
||||
choice.inputsList = new ArrayList(sizeof(VariantInputData));
|
||||
JSON_Array entities = view_as<JSON_Array>(choiceData.GetObject("entities"));
|
||||
if(entities != null) {
|
||||
choice.forcedScenes = new ArrayList(ByteCountToCells(MAX_SCENE_NAME_LENGTH));
|
||||
// Load in any variant-based entities
|
||||
if(choiceData.HasKey("entities")) {
|
||||
JSONArray entities = view_as<JSONArray>(choiceData.Get("entities"));
|
||||
for(int i = 0; i < entities.Length; i++) {
|
||||
// Parses entities and loads to choice.entities
|
||||
loadChoiceEntity(choice.entities, entities.GetObject(i));
|
||||
loadChoiceEntity(choice.entities, view_as<JSONObject>(entities.Get(i)));
|
||||
}
|
||||
delete entities;
|
||||
}
|
||||
JSON_Array inputsList = view_as<JSON_Array>(choiceData.GetObject("inputs"));
|
||||
if(inputsList != null) {
|
||||
// Load in any entities that the scene has
|
||||
if(extraEntities != null) {
|
||||
for(int i = 0; i < extraEntities.Length; i++) {
|
||||
// Parses entities and loads to choice.entities
|
||||
loadChoiceEntity(choice.entities, view_as<JSONObject>(extraEntities.Get(i)));
|
||||
}
|
||||
delete extraEntities;
|
||||
}
|
||||
// Load all inputs
|
||||
if(choiceData.HasKey("inputs")) {
|
||||
JSONArray inputsList = view_as<JSONArray>(choiceData.Get("inputs"));
|
||||
for(int i = 0; i < inputsList.Length; i++) {
|
||||
loadChoiceInput(choice.inputsList, inputsList.GetObject(i));
|
||||
loadChoiceInput(choice.inputsList, view_as<JSONObject>(inputsList.Get(i)));
|
||||
}
|
||||
delete inputsList;
|
||||
}
|
||||
if(choiceData.HasKey("force_scenes")) {
|
||||
JSONArray scenes = view_as<JSONArray>(choiceData.Get("force_scenes"));
|
||||
char sceneId[32];
|
||||
for(int i = 0; i < scenes.Length; i++) {
|
||||
scenes.GetString(i, sceneId, sizeof(sceneId));
|
||||
choice.forcedScenes.PushString(sceneId);
|
||||
}
|
||||
delete scenes;
|
||||
}
|
||||
scene.variants.PushArray(choice);
|
||||
}
|
||||
|
||||
void loadChoiceInput(ArrayList list, JSON_Object inputData) {
|
||||
void loadChoiceInput(ArrayList list, JSONObject inputData) {
|
||||
VariantInputData input;
|
||||
// Check classname -> targetname -> hammerid
|
||||
if(!inputData.GetString("classname", input.name, sizeof(input.name))) {
|
||||
|
@ -527,7 +905,7 @@ void loadChoiceInput(ArrayList list, JSON_Object inputData) {
|
|||
list.PushArray(input);
|
||||
}
|
||||
|
||||
void loadLumpData(ArrayList list, JSON_Object inputData) {
|
||||
void loadLumpData(ArrayList list, JSONObject inputData) {
|
||||
LumpEditData input;
|
||||
// Check classname -> targetname -> hammerid
|
||||
if(!inputData.GetString("classname", input.name, sizeof(input.name))) {
|
||||
|
@ -553,7 +931,7 @@ void loadLumpData(ArrayList list, JSON_Object inputData) {
|
|||
list.PushArray(input);
|
||||
}
|
||||
|
||||
void loadChoiceEntity(ArrayList list, JSON_Object entityData) {
|
||||
void loadChoiceEntity(ArrayList list, JSONObject entityData) {
|
||||
VariantEntityData entity;
|
||||
entityData.GetString("model", entity.model, sizeof(entity.model));
|
||||
if(!entityData.GetString("type", entity.type, sizeof(entity.type))) {
|
||||
|
@ -569,18 +947,20 @@ void loadChoiceEntity(ArrayList list, JSON_Object entityData) {
|
|||
list.PushArray(entity);
|
||||
}
|
||||
|
||||
void GetVector(JSON_Object obj, const char[] key, float out[3]) {
|
||||
JSON_Array vecArray = view_as<JSON_Array>(obj.GetObject(key));
|
||||
bool GetVector(JSONObject obj, const char[] key, float out[3]) {
|
||||
if(!obj.HasKey(key)) return false;
|
||||
JSONArray vecArray = view_as<JSONArray>(obj.Get(key));
|
||||
if(vecArray != null) {
|
||||
out[0] = vecArray.GetFloat(0);
|
||||
out[1] = vecArray.GetFloat(1);
|
||||
out[2] = vecArray.GetFloat(2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetColor(JSON_Object obj, const char[] key, int out[4]) {
|
||||
JSON_Array vecArray = view_as<JSON_Array>(obj.GetObject(key));
|
||||
if(vecArray != null) {
|
||||
void GetColor(JSONObject obj, const char[] key, int out[4], int defaultColor[4] = { 255, 255, 255, 255 }) {
|
||||
if(obj.HasKey(key)) {
|
||||
JSONArray vecArray = view_as<JSONArray>(obj.Get(key));
|
||||
out[0] = vecArray.GetInt(0);
|
||||
out[1] = vecArray.GetInt(1);
|
||||
out[2] = vecArray.GetInt(2);
|
||||
|
@ -589,10 +969,7 @@ void GetColor(JSON_Object obj, const char[] key, int out[4]) {
|
|||
else
|
||||
out[3] = 255;
|
||||
} else {
|
||||
out[0] = 255;
|
||||
out[1] = 255;
|
||||
out[2] = 255;
|
||||
out[3] = 255;
|
||||
out = defaultColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -600,6 +977,8 @@ void selectScenes(int flags = 0) {
|
|||
SceneData scene;
|
||||
StringMap groups = new StringMap();
|
||||
ArrayList list;
|
||||
// Select and spawn non-group scenes
|
||||
// TODO: refactor to use .scenesKv
|
||||
for(int i = 0; i < g_MapData.scenes.Length; i++) {
|
||||
g_MapData.scenes.GetArray(i, scene);
|
||||
// TODO: Exclusions
|
||||
|
@ -607,6 +986,7 @@ void selectScenes(int flags = 0) {
|
|||
if(scene.group[0] == '\0') {
|
||||
selectScene(scene, flags);
|
||||
} else {
|
||||
// Load it into group list
|
||||
if(!groups.GetValue(scene.group, list)) {
|
||||
list = new ArrayList();
|
||||
}
|
||||
|
@ -615,25 +995,61 @@ void selectScenes(int flags = 0) {
|
|||
}
|
||||
}
|
||||
|
||||
// Iterate through groups and select a random scene:
|
||||
StringMapSnapshot snapshot = groups.Snapshot();
|
||||
char key[MAX_SCENE_NAME_LENGTH];
|
||||
for(int i = 0; i < snapshot.Length; i++) {
|
||||
snapshot.GetKey(i, key, sizeof(key));
|
||||
groups.GetValue(key, list);
|
||||
// Select a random scene from the group:
|
||||
int index = GetURandomInt() % list.Length;
|
||||
index = list.Get(index);
|
||||
g_MapData.scenes.GetArray(index, scene);
|
||||
|
||||
Debug("Selected scene \"%s\" for group %s (%d members)", scene.name, key, list.Length);
|
||||
selectScene(scene, flags);
|
||||
delete list;
|
||||
}
|
||||
// Traverse active scenes, loading any other scene it requires (via .force_scenes)
|
||||
ActiveSceneData aScene;
|
||||
SceneVariantData choice;
|
||||
ArrayList forcedScenes = new ArrayList(ByteCountToCells(MAX_SCENE_NAME_LENGTH));
|
||||
for(int i = 0; i < g_MapData.activeScenes.Length; i++) {
|
||||
g_MapData.activeScenes.GetArray(i, aScene);
|
||||
g_MapData.scenes.GetArray(i, scene);
|
||||
scene.variants.GetArray(aScene.variantIndex, choice);
|
||||
if(choice.forcedScenes != null) {
|
||||
for(int j = 0; j < choice.forcedScenes.Length; j++) {
|
||||
choice.forcedScenes.GetString(j, key, sizeof(key));
|
||||
forcedScenes.PushString(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Iterate and activate any forced scenes
|
||||
for(int i = 0; i < forcedScenes.Length; i++) {
|
||||
forcedScenes.GetString(i, key, sizeof(key));
|
||||
// Check if scene was already loaded
|
||||
bool isSceneAlreadyLoaded = false;
|
||||
for(int j = 0; j < g_MapData.activeScenes.Length; i++) {
|
||||
g_MapData.activeScenes.GetArray(j, aScene);
|
||||
if(StrEqual(aScene.name, key)) {
|
||||
isSceneAlreadyLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(isSceneAlreadyLoaded) continue;
|
||||
g_MapData.scenesKv.GetArray(key, scene, sizeof(scene));
|
||||
selectScene(scene, flags | view_as<int>(FLAG_FORCE_ACTIVE));
|
||||
}
|
||||
|
||||
delete forcedScenes;
|
||||
delete snapshot;
|
||||
delete groups;
|
||||
}
|
||||
|
||||
void selectScene(SceneData scene, int flags) {
|
||||
// Use the .chance field unless FLAG_ALL_SCENES is set
|
||||
if(~flags & view_as<int>(FLAG_ALL_SCENES) && GetURandomFloat() > scene.chance) {
|
||||
// Use the .chance field unless FLAG_ALL_SCENES or FLAG_FORCE_ACTIVE is set
|
||||
if(~flags & view_as<int>(FLAG_ALL_SCENES) && ~flags & view_as<int>(FLAG_FORCE_ACTIVE) && GetURandomFloat() > scene.chance) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -645,20 +1061,26 @@ void selectScene(SceneData scene, int flags) {
|
|||
ArrayList choices = new ArrayList();
|
||||
SceneVariantData choice;
|
||||
int index;
|
||||
Debug("Scene %s has %d variants", scene.name, scene.variants.Length);
|
||||
// Weighted random: Push N times dependent on weight
|
||||
for(int i = 0; i < scene.variants.Length; i++) {
|
||||
scene.variants.GetArray(i, choice);
|
||||
if(flags & view_as<int>(FLAG_ALL_VARIANTS)) {
|
||||
spawnVariant(choice);
|
||||
} else {
|
||||
if(choice.weight <= 0) {
|
||||
PrintToServer("Warn: Variant %d in scene %s has invalid weight", i, scene.name);
|
||||
continue;
|
||||
}
|
||||
for(int c = 0; c < choice.weight; c++) {
|
||||
choices.Push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
Debug("Total choices: %d", choices.Length);
|
||||
if(flags & view_as<int>(FLAG_ALL_VARIANTS)) {
|
||||
delete choices;
|
||||
} else {
|
||||
} else if(choices.Length > 0) {
|
||||
index = GetURandomInt() % choices.Length;
|
||||
index = choices.Get(index);
|
||||
delete choices;
|
||||
|
@ -666,7 +1088,6 @@ void selectScene(SceneData scene, int flags) {
|
|||
scene.variants.GetArray(index, choice);
|
||||
spawnVariant(choice);
|
||||
}
|
||||
|
||||
ActiveSceneData aScene;
|
||||
strcopy(aScene.name, sizeof(aScene.name), scene.name);
|
||||
aScene.variantIndex = index;
|
||||
|
|
|
@ -20,6 +20,9 @@ int connectAttempts;
|
|||
authState g_authState;
|
||||
JSONObject g_globalVars;
|
||||
|
||||
StringMap actionFallbackHandlers; // namespace -> action name has no handler, falls to this.
|
||||
StringMap actionNamespaceHandlers; // { namespace: { [action name] -> handler } }
|
||||
|
||||
enum authState {
|
||||
AuthError = -1,
|
||||
NotAuthorized,
|
||||
|
@ -53,8 +56,16 @@ char OUT_EVENT_IDS[view_as<int>(Event_Invalid)][] = {
|
|||
char steamidCache[MAXPLAYERS+1][32];
|
||||
|
||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) {
|
||||
CreateNative("UIElement.Send", Native_UpdateUI);
|
||||
CreateNative("TempUI.Send", Native_UpdateTempUI);
|
||||
RegPluginLibrary("overlay");
|
||||
|
||||
CreateNative("IsOverlayConnected", Native_IsOverlayConnected);
|
||||
CreateNative("RegisterActionAnyHandler", Native_ActionHandler);
|
||||
CreateNative("RegisterActionHandler", Native_ActionHandler);
|
||||
|
||||
CreateNative("UIElement.SendAll", Native_UpdateUI);
|
||||
CreateNative("UIElement.SendTo", Native_UpdateUI);
|
||||
CreateNative("TempUI.SendAll", Native_UpdateTempUI);
|
||||
CreateNative("TempUI.SendTo", Native_UpdateTempUI);
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
|
@ -64,6 +75,9 @@ public void OnPluginStart() {
|
|||
SetFailState("This plugin is for L4D/L4D2 only.");
|
||||
}
|
||||
|
||||
actionFallbackHandlers = new StringMap();
|
||||
actionNamespaceHandlers = new StringMap();
|
||||
|
||||
g_globalVars = new JSONObject();
|
||||
|
||||
cvarManagerUrl = CreateConVar("sm_overlay_manager_url", "ws://localhost:3011/socket", "");
|
||||
|
@ -171,6 +185,7 @@ void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast)
|
|||
if(GetClientCount(false) == 0) {
|
||||
DisconnectManager();
|
||||
}
|
||||
steamidCache[client][0] = '\0';
|
||||
}
|
||||
|
||||
void OnWSConnect(WebSocket ws, any arg) {
|
||||
|
@ -210,12 +225,78 @@ void OnWSJson(WebSocket ws, JSON message, any data) {
|
|||
message.ToString(buffer, sizeof(buffer));
|
||||
PrintToServer("[Overlay] Error: %s", buffer);
|
||||
} else {
|
||||
char type[32];
|
||||
obj.GetString("type", type, sizeof(type));
|
||||
if(StrEqual(type, "action")) {
|
||||
OnAction(obj);
|
||||
}
|
||||
|
||||
char buffer[2048];
|
||||
message.ToString(buffer, sizeof(buffer));
|
||||
PrintToServer("[Overlay] Got JSON: %s", buffer);
|
||||
}
|
||||
}
|
||||
|
||||
stock int ExplodeStringToArrayList(const char[] text, const char[] split, ArrayList buffers, int maxStringLength) {
|
||||
int reloc_idx, idx, total;
|
||||
|
||||
if (buffers == null || !split[0]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char[] item = new char[maxStringLength];
|
||||
while ((idx = SplitString(text[reloc_idx], split, item, maxStringLength)) != -1) {
|
||||
reloc_idx += idx;
|
||||
++total;
|
||||
buffers.PushString(item);
|
||||
}
|
||||
++total;
|
||||
buffers.PushString(text[reloc_idx]);
|
||||
|
||||
return buffers.Length;
|
||||
}
|
||||
|
||||
void OnAction(JSONObject obj) {
|
||||
char steamid[32];
|
||||
obj.GetString("steamid", steamid, sizeof(steamid));
|
||||
char ns[64];
|
||||
obj.GetString("namespace", ns, sizeof(ns));
|
||||
char id[64];
|
||||
obj.GetString("elem_id", id, sizeof(id));
|
||||
char action[256];
|
||||
obj.GetString("action", action, sizeof(action));
|
||||
|
||||
int client = FindClientBySteamId2(steamid);
|
||||
|
||||
StringMap nsHandler;
|
||||
PrivateForward fwd;
|
||||
if(!actionNamespaceHandlers.GetValue(ns, nsHandler) || !nsHandler.GetValue(id, fwd)) {
|
||||
if(!actionFallbackHandlers.GetValue(ns, fwd)) {
|
||||
// No handler or catch all namespace handler
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList args = new ArrayList(ACTION_ARG_LENGTH);
|
||||
ExplodeStringToArrayList(action, " ", args, ACTION_ARG_LENGTH);
|
||||
UIActionEvent event = UIActionEvent(args);
|
||||
|
||||
Call_StartForward(fwd);
|
||||
Call_PushCell(event);
|
||||
Call_PushCell(client);
|
||||
Call_Finish();
|
||||
event._Delete();
|
||||
}
|
||||
|
||||
int FindClientBySteamId2(const char[] steamid) {
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(StrEqual(steamidCache[i], steamid)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void ConnectManager() {
|
||||
DisconnectManager();
|
||||
|
@ -281,11 +362,15 @@ void SendEvent_UpdateUI(const char[] elemNamespace, const char[] elemId, bool vi
|
|||
}
|
||||
|
||||
//SendTempUI(int client, const char[] id, int lifetime, JSONObject element);
|
||||
bool Native_SendTempUI(Handle plugin, int numParams) {
|
||||
any Native_SendTempUI(Handle plugin, int numParams) {
|
||||
if(!isManagerReady()) return false;
|
||||
|
||||
int client = GetNativeCell(1);
|
||||
if(steamidCache[client][0] == '\0') return false;
|
||||
if (client <= 0 || client > MaxClients) {
|
||||
return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index (%d)", client);
|
||||
} else if (!IsClientConnected(client) || steamidCache[client][0] == '\0') {
|
||||
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not connected/authorized yet", client);
|
||||
}
|
||||
|
||||
char id[64];
|
||||
GetNativeString(2, id, sizeof(id));
|
||||
|
@ -299,7 +384,7 @@ bool Native_SendTempUI(Handle plugin, int numParams) {
|
|||
}
|
||||
|
||||
//ShowUI(int client, const char[] elemNamespace, const char[] elemId, JSONObject variables);
|
||||
bool Native_ShowUI(Handle plugin, int numParams) {
|
||||
any Native_ShowUI(Handle plugin, int numParams) {
|
||||
if(!isManagerReady()) return false;
|
||||
|
||||
char elemNamespace[64], id[64];
|
||||
|
@ -313,7 +398,7 @@ bool Native_ShowUI(Handle plugin, int numParams) {
|
|||
}
|
||||
|
||||
//HideUI(int client, const char[] elemNamespace, const char[] elemId);
|
||||
bool Native_HideUI(Handle plugin, int numParams) {
|
||||
any Native_HideUI(Handle plugin, int numParams) {
|
||||
if(!isManagerReady()) return false;
|
||||
|
||||
char elemNamespace[64], id[64];
|
||||
|
@ -325,7 +410,7 @@ bool Native_HideUI(Handle plugin, int numParams) {
|
|||
}
|
||||
|
||||
//PlayAudio(int client, const char[] url);
|
||||
bool Native_PlayAudio(Handle plugin, int numParams) {
|
||||
any Native_PlayAudio(Handle plugin, int numParams) {
|
||||
if(!isManagerReady()) return false;
|
||||
|
||||
char url[256];
|
||||
|
@ -335,27 +420,92 @@ bool Native_PlayAudio(Handle plugin, int numParams) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Native_UpdateUI(Handle plugin, int numParams) {
|
||||
any Native_UpdateUI(Handle plugin, int numParams) {
|
||||
if(!isManagerReady()) return false;
|
||||
|
||||
UIElement elem = GetNativeCell(1);
|
||||
JSONObject obj = view_as<JSONObject>(elem);
|
||||
|
||||
JSONArray arr = view_as<JSONArray>(obj.Get("steamids"));
|
||||
if(numParams == 0) {
|
||||
arr.Clear();
|
||||
} else if(numParams == 1) {
|
||||
int client = GetNativeCell(2);
|
||||
if (client <= 0 || client > MaxClients) {
|
||||
return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index (%d)", client);
|
||||
} else if (!IsClientConnected(client) || steamidCache[client][0] == '\0') {
|
||||
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not connected/authorized yet", client);
|
||||
}
|
||||
arr.PushString(steamidCache[client]);
|
||||
}
|
||||
|
||||
g_ws.Write(view_as<JSON>(elem));
|
||||
arr.Clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Native_UpdateTempUI(Handle plugin, int numParams) {
|
||||
any Native_UpdateTempUI(Handle plugin, int numParams) {
|
||||
if(!isManagerReady()) return false;
|
||||
|
||||
TempUI elem = GetNativeCell(1);
|
||||
JSONObject obj = view_as<JSONObject>(elem);
|
||||
|
||||
JSONArray arr = view_as<JSONArray>(obj.Get("steamids"));
|
||||
if(numParams == 0) {
|
||||
arr.Clear();
|
||||
} else if(numParams == 1) {
|
||||
int client = GetNativeCell(2);
|
||||
if (client <= 0 || client > MaxClients) {
|
||||
return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index (%d)", client);
|
||||
} else if (!IsClientConnected(client) || steamidCache[client][0] == '\0') {
|
||||
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not connected/authorized yet", client);
|
||||
}
|
||||
arr.PushString(steamidCache[client]);
|
||||
}
|
||||
|
||||
g_ws.Write(view_as<JSON>(elem));
|
||||
arr.Clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//IsOverlayConnected();
|
||||
bool Native_IsOverlayConnected(Handle plugin, int numParams) {
|
||||
any Native_IsOverlayConnected(Handle plugin, int numParams) {
|
||||
return isManagerReady();
|
||||
}
|
||||
|
||||
//RegisterActionHandler
|
||||
//RegisterActionAnyHandler
|
||||
any Native_ActionHandler(Handle plugin, int numParams) {
|
||||
char ns[64];
|
||||
GetNativeString(1, ns, sizeof(ns));
|
||||
|
||||
if(numParams == 3) {
|
||||
// RegisterActionHandler
|
||||
StringMap nsHandlers;
|
||||
if(!actionNamespaceHandlers.GetValue(ns, nsHandlers)) {
|
||||
nsHandlers = new StringMap();
|
||||
}
|
||||
|
||||
char actionId[64];
|
||||
GetNativeString(2, actionId, sizeof(actionId));
|
||||
|
||||
PrivateForward fwd;
|
||||
if(!nsHandlers.GetValue(actionId, fwd)) {
|
||||
fwd = new PrivateForward(ET_Ignore, Param_Cell);
|
||||
}
|
||||
fwd.AddFunction(INVALID_HANDLE, GetNativeFunction(3));
|
||||
nsHandlers.SetValue(actionId, fwd);
|
||||
} else {
|
||||
// RegisterActionAnyHandler
|
||||
|
||||
PrivateForward fwd;
|
||||
if(!actionFallbackHandlers.GetValue(ns, fwd)) {
|
||||
fwd = new PrivateForward(ET_Ignore, Param_Cell);
|
||||
}
|
||||
fwd.AddFunction(INVALID_HANDLE, GetNativeFunction(2));
|
||||
actionFallbackHandlers.SetValue(ns, fwd);
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -242,15 +242,12 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
|
|||
PrintToChat(client, "Note cancelled.");
|
||||
} else {
|
||||
int size = 2 * strlen(sArgs) + 1;
|
||||
char[] sArgsTrimmed = new char[size];
|
||||
DB.Escape(sArgs, sArgsTrimmed, size);
|
||||
TrimString(sArgsTrimmed);
|
||||
char buffer[32];
|
||||
GetClientAuthId(client, AuthId_Steam2, buffer, sizeof(buffer));
|
||||
// TODO: escape content
|
||||
DB.Format(query, sizeof(query), "INSERT INTO `notes` (steamid, markedBy, content) VALUES ('%s', '%s', '%s')", menuNoteTarget, buffer, sArgsTrimmed);
|
||||
DB.Format(query, sizeof(query), "INSERT INTO `notes` (steamid, markedBy, content) VALUES ('%s', '%s', '%s')", menuNoteTarget, buffer, sArgs);
|
||||
DB.Query(DB_AddNote, query);
|
||||
LogAction(client, -1, "added note for \"%s\" (%s): \"%s\"", client, menuNoteTargetName, menuNoteTarget, sArgsTrimmed);
|
||||
LogAction(client, -1, "added note for \"%s\" (%s): \"%s\"", client, menuNoteTargetName, menuNoteTarget, sArgs);
|
||||
Format(buffer, sizeof(buffer), "%N: ", client);
|
||||
CShowActivity2(client, buffer, "added a note for {green}%s: {default}\"%s\"", menuNoteTargetName, sArgs);
|
||||
}
|
||||
|
@ -310,10 +307,7 @@ public Action Command_AddNote(int client, int args) {
|
|||
char authMarker[32];
|
||||
if(client > 0)
|
||||
GetClientAuthId(client, AuthId_Steam2, authMarker, sizeof(authMarker));
|
||||
int size = 2 * strlen(reason) + 1;
|
||||
char[] content = new char[size];
|
||||
DB.Escape(reason, content, size);
|
||||
DB.Format(query, sizeof(query), "INSERT INTO `notes` (steamid, markedBy, content) VALUES ('%s', '%s', '%s')", auth, authMarker, content);
|
||||
DB.Format(query, sizeof(query), "INSERT INTO `notes` (steamid, markedBy, content) VALUES ('%s', '%s', '%s')", auth, authMarker, reason);
|
||||
DB.Query(DB_AddNote, query);
|
||||
LogAction(client, target_list[0], "\"%L\" added note for \"%L\": \"%s\"", client, target_list[0], reason);
|
||||
CShowActivity(client, "added a note for {green}%N: {default}\"%s\"", target_list[0], reason);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue