diff --git a/plugins/L4D2Tools.smx b/plugins/L4D2Tools.smx index 30d6c5f..a9a19f5 100644 Binary files a/plugins/L4D2Tools.smx and b/plugins/L4D2Tools.smx differ diff --git a/plugins/activitymonitor.smx b/plugins/activitymonitor.smx index 69217ec..5a7a712 100644 Binary files a/plugins/activitymonitor.smx and b/plugins/activitymonitor.smx differ diff --git a/plugins/adminpanel.smx b/plugins/adminpanel.smx index 743e461..5e2f74b 100644 Binary files a/plugins/adminpanel.smx and b/plugins/adminpanel.smx differ diff --git a/plugins/l4d2_editor.smx b/plugins/l4d2_editor.smx index 95bfac7..a974556 100644 Binary files a/plugins/l4d2_editor.smx and b/plugins/l4d2_editor.smx differ diff --git a/plugins/l4d2_hats.smx b/plugins/l4d2_hats.smx index 298fbf3..a02b46a 100644 Binary files a/plugins/l4d2_hats.smx and b/plugins/l4d2_hats.smx differ diff --git a/plugins/l4d2_randomizer.smx b/plugins/l4d2_randomizer.smx index 836ff1b..7f667ce 100644 Binary files a/plugins/l4d2_randomizer.smx and b/plugins/l4d2_randomizer.smx differ diff --git a/scripting/L4D2Tools.sp b/scripting/L4D2Tools.sp index d643de1..bc33025 100644 --- a/scripting/L4D2Tools.sp +++ b/scripting/L4D2Tools.sp @@ -5,10 +5,11 @@ #define PLUGIN_VERSION "1.0" -#define PRECACHE_SOUNDS_COUNT 4 +#define PRECACHE_SOUNDS_COUNT 5 char PRECACHE_SOUNDS[PRECACHE_SOUNDS_COUNT][] = { "custom/xen_teleport.mp3", "custom/mariokartmusic.mp3", + "custom/airhorn.mp3", "custom/spookyscaryskeletons.mp3", "custom/wearenumberone2.mp3", }; diff --git a/scripting/activitymonitor.sp b/scripting/activitymonitor.sp index e63f560..6a424bc 100644 --- a/scripting/activitymonitor.sp +++ b/scripting/activitymonitor.sp @@ -248,6 +248,14 @@ public void Event_L4D2_Death(Event event, const char[] name, bool dontBroadcast) if(IsFakeClient(attacker)) GetClientName(attacker, attackerName, sizeof(attackerName)); else GetClientAuthId(attacker, AuthId_Steam2, attackerName, sizeof(attackerName)); + if(GetClientTeam(attacker) == 2) { + char weaponName[32]; + event.GetString("weapon", weaponName, sizeof(weaponName)); + if(weaponName[0] != '\0') { + AddLogCustom("STATE", attackerName, victimName, "\"%L\" killed \"%L\" with \"%s\"", attacker, victim, weaponName); + return; + } + } AddLogCustom("STATE", attackerName, victimName, "\"%L\" killed \"%L\"", attacker, victim); } else { AddLogCustom("STATE", "", victimName, "\"%L\" died", victim); @@ -267,7 +275,15 @@ public void Event_L4D2_Incapped(Event event, const char[] name, bool dontBroadca if(attacker > 0 && attacker != victim) { if(IsFakeClient(attacker)) GetClientName(attacker, attackerName, sizeof(attackerName)); else GetClientAuthId(attacker, AuthId_Steam2, attackerName, sizeof(attackerName)); - + + if(GetClientTeam(attacker) == 2) { + char weaponName[32]; + event.GetString("weapon", weaponName, sizeof(weaponName)); + if(weaponName[0] != '\0') { + AddLogCustom("STATE", attackerName, victimName, "\"%L\" incapped \"%L\" with \"%s\"", attacker, victim, weaponName); + return; + } + } AddLogCustom("STATE", attackerName, victimName, "\"%L\" incapped \"%L\"", attacker, victim); } else { AddLogCustom("STATE", "", victimName, "\"%L\" was incapped", victim); diff --git a/scripting/include/editor/props/methods.sp b/scripting/include/editor/props/methods.sp index f322028..159b4f3 100644 --- a/scripting/include/editor/props/methods.sp +++ b/scripting/include/editor/props/methods.sp @@ -203,6 +203,7 @@ void LoadFolder(ArrayList parent, const char[] rootPath) { DirectoryListing listing = OpenDirectory(rootPath); if(listing == null) { LogError("Cannot open \"%s\"", rootPath); + return; } while(listing.GetNext(buffer, sizeof(buffer), fileType)) { if(fileType == FileType_Directory) { diff --git a/scripting/include/hats/hats.sp b/scripting/include/hats/hats.sp index 5734a1a..e51ef96 100644 --- a/scripting/include/hats/hats.sp +++ b/scripting/include/hats/hats.sp @@ -135,7 +135,7 @@ Action Command_DoAHat(int client, int args) { char sizeStr[4]; GetCmdArg(2, sizeStr, sizeof(sizeStr)); float size = StringToFloat(sizeStr); - if(size == 0.0) { + if(size <= 0.0) { ReplyToCommand(client, "[Hats] Invalid size"); return Plugin_Handled; } @@ -335,7 +335,12 @@ Action Command_DoAHat(int client, int args) { } else { // Find a new hatable entity int flags = 0; - entity = GetLookingEntity(client, Filter_ValidHats); + if(args > 0 && isForced) { + char arg[16]; + entity = GetCmdArgInt(1); + } else { + entity = GetLookingEntity(client, Filter_ValidHats); + } if(entity <= 0) { PrintCenterText(client, "[Hats] No entity found"); return Plugin_Handled; diff --git a/scripting/include/randomizer/caralarm.sp b/scripting/include/randomizer/caralarm.sp new file mode 100644 index 0000000..aee8f1c --- /dev/null +++ b/scripting/include/randomizer/caralarm.sp @@ -0,0 +1,427 @@ +int SpawnCar(VariantEntityData entity) { + if(entity.model[0] == '\0') { + LogError("Missing model for entity with type \"%s\"", entity.type); + return -1; + } + PrecacheModel(entity.model); + int vehicle; + + if(StrEqual(entity.type, "_car_alarm")) { + vehicle = SpawnAlarmCar(entity.model, entity.origin, entity.angles, entity.color); + return vehicle; + } + + char glassModel[64]; + strcopy(glassModel, sizeof(glassModel), entity.type); + ReplaceString(glassModel, sizeof(glassModel), ".mdl", "_glass.mdl"); + if(StrEqual(entity.type, "_car_physics")) { + vehicle = CreateProp("prop_physics", entity.model, entity.origin, entity.angles); + } else { + vehicle = CreateProp("prop_dynamic", entity.model, entity.origin, entity.angles); + } + if(PrecacheModel(glassModel)) { + int glass = CreateProp(glassModel, entity.model, entity.origin, entity.angles); + SetVariantString("!activator"); + AcceptEntityInput(glass, "SetParent", vehicle); + } + SetEntityRenderColor(vehicle, GetRandomInt(0, 255), GetRandomInt(0, 255), GetRandomInt(0, 255)); + return vehicle; +} + + +/** +// ==================================================================================================== +:::BEGIN::: -> Source Code (with changes) from: +* DieTeetasse - [L4D1&2] Spawn Alarmcars plugin https://forums.alliedmods.net/showthread.php?t=139352 +* Marttt - [L4D1 & L4D2] Replace Cars Into Car Alarms plugin https://forums.alliedmods.net/showthread.php?p=2731868 +// ==================================================================================================== +*/ + +/****************************************************************************************************/ + +#define DISTANCE_FRONT 101.0 +#define DISTANCE_SIDETURN 34.0 +#define DISTANCE_UPFRONT 29.0 +#define DISTANCE_BACK 103.0 +#define DISTANCE_SIDE 27.0 +#define DISTANCE_UPBACK 31.0 +#define SOUND_CAR_ALARM "vehicles/car_alarm/car_alarm.wav" +#define SOUND_CAR_ALARM_CHIRP2 "vehicles/car_alarm/car_alarm_chirp2.wav" + +#define COLOR_YELLOWLIGHT "224 162 44" +#define COLOR_REDLIGHT "255 13 19" +#define COLOR_WHITELIGHT "252 243 226" +#define ALARMCAR_GLOW_SPRITE "sprites/glow.vmt" + +int SpawnAlarmCar(const char[] model, float vPos[3], float vAng[3], int color[4] = { 255, 255, 255, 255}) +{ + PrecacheModel(model); + PrecacheModel(ALARMCAR_GLOW_SPRITE, true); + PrecacheSound(SOUND_CAR_ALARM, true); + PrecacheSound(SOUND_CAR_ALARM_CHIRP2, true); + + char carName[64]; + char glassOnName[64]; + char glassOffName[64]; + char timerName[64]; + char alarmSoundName[64]; + char chirpSoundName[64]; + char lightsName[64]; + char headlightsName[64]; + char remarkName[64]; + char gameEventName[64]; + + // create car + int carEntity = CreateEntityByName("prop_car_alarm"); + + FormatEx(carName, sizeof(carName), "randomizer_car_%d", carEntity); + FormatEx(glassOnName, sizeof(glassOnName), "randomizer_car_glasson_%d", carEntity); + FormatEx(glassOffName, sizeof(glassOffName), "randomizer_car_glassoff_%d", carEntity); + FormatEx(timerName, sizeof(timerName), "randomizer_car_alarmtimer_%d", carEntity); + FormatEx(alarmSoundName, sizeof(alarmSoundName), "randomizer_car_alarmsound_%d", carEntity); + FormatEx(chirpSoundName, sizeof(chirpSoundName), "randomizer_car_chirpsound_%d", carEntity); + FormatEx(lightsName, sizeof(lightsName), "randomizer_car_lights_%d", carEntity); + FormatEx(headlightsName, sizeof(headlightsName), "randomizer_car_headlights_%d", carEntity); + FormatEx(remarkName, sizeof(remarkName), "randomizer_car_remark_%d", carEntity); + FormatEx(gameEventName, sizeof(gameEventName), "randomizer_car_gameevent_%d", carEntity); + char tempString[128]; + + DispatchKeyValue(carEntity, "targetname", carName); + DispatchKeyValue(carEntity, "model", model); + Format(tempString, sizeof(tempString), "%d %d %d %d", color[0], color[1], color[2], color[3]); + DispatchKeyValue(carEntity, "rendercolor", tempString); + Debug("spawning alarm car ent%d \"%s\" (m=%s) at %.0f %.0f %.0f", carEntity, carName, model, vPos[0], vPos[1], vPos[2]); + + Format(tempString, sizeof(tempString), "%s,PlaySound,,0.2,-1", chirpSoundName); + DispatchKeyValue(carEntity, "OnCarAlarmChirpStart", tempString); + Format(tempString, sizeof(tempString), "%s,ShowSprite,,0.2,-1", lightsName); + DispatchKeyValue(carEntity, "OnCarAlarmChirpStart", tempString); + Format(tempString, sizeof(tempString), "%s,HideSprite,,0.7,-1", lightsName); + DispatchKeyValue(carEntity, "OnCarAlarmChirpEnd", tempString); + Format(tempString, sizeof(tempString), "%s,Enable,,0,-1", timerName); + DispatchKeyValue(carEntity, "OnCarAlarmStart", tempString); + Format(tempString, sizeof(tempString), "%s,PlaySound,,0,-1", alarmSoundName); + DispatchKeyValue(carEntity, "OnCarAlarmStart", tempString); + Format(tempString, sizeof(tempString), "%s,Enable,,0,-1", glassOffName); + DispatchKeyValue(carEntity, "OnCarAlarmStart", tempString); + DispatchKeyValue(carEntity, "OnHitByTank", tempString); + Format(tempString, sizeof(tempString), "%s,Kill,,0,-1", glassOnName); + DispatchKeyValue(carEntity, "OnCarAlarmStart", tempString); + DispatchKeyValue(carEntity, "OnHitByTank", tempString); + Format(tempString, sizeof(tempString), "%s,Kill,,0,-1", timerName); + DispatchKeyValue(carEntity, "OnCarAlarmEnd", tempString); + DispatchKeyValue(carEntity, "OnHitByTank", tempString); + Format(tempString, sizeof(tempString), "%s,Kill,,0,-1", alarmSoundName); + DispatchKeyValue(carEntity, "OnCarAlarmEnd", tempString); + DispatchKeyValue(carEntity, "OnHitByTank", tempString); + Format(tempString, sizeof(tempString), "%s,Kill,,0,-1", chirpSoundName); + DispatchKeyValue(carEntity, "OnCarAlarmEnd", tempString); + DispatchKeyValue(carEntity, "OnHitByTank", tempString); + Format(tempString, sizeof(tempString), "%s,Kill,,0,-1", lightsName); + DispatchKeyValue(carEntity, "OnCarAlarmEnd", tempString); + DispatchKeyValue(carEntity, "OnHitByTank", tempString); + Format(tempString, sizeof(tempString), "%s,Kill,,0,-1", headlightsName); + DispatchKeyValue(carEntity, "OnCarAlarmEnd", tempString); + DispatchKeyValue(carEntity, "OnHitByTank", tempString); + Format(tempString, sizeof(tempString), "%s,Kill,,0,-1", remarkName); + DispatchKeyValue(carEntity, "OnCarAlarmEnd", tempString); + DispatchKeyValue(carEntity, "OnHitByTank", tempString); + Format(tempString, sizeof(tempString), "%s,Kill,,0,-1", gameEventName); + DispatchKeyValue(carEntity, "OnCarAlarmEnd", tempString); + DispatchKeyValue(carEntity, "OnHitByTank", tempString); + DispatchKeyValueVector(carEntity, "origin", vPos); + DispatchKeyValueVector(carEntity, "angles", vAng); + DispatchSpawn(carEntity); + + // create glasses + strcopy(tempString, sizeof(tempString), model); + ReplaceString(tempString, sizeof(tempString), ".mdl", "_glass.mdl"); + if(PrecacheModel(tempString)) + CreateGlass(tempString, glassOnName, false, vPos, vAng, carName); + // CreateGlass(glassOffName, true, vPos, vAng, carName); + + CreateSound(alarmSoundName, "16", "Car.Alarm", vPos, carName); + CreateSound(chirpSoundName, "48", "Car.Alarm.Chirp2", vPos, carName); + + CreateLights(lightsName, vPos, vAng, carName); + + CreateHeadlights(headlightsName, vPos, vAng, carName); + + CreateLogicTimer(timerName, lightsName, headlightsName, vPos, carName); + + CreateRemark(remarkName, vPos, vAng, carName); + + CreateGameEvent(gameEventName, vPos, vAng, carName); + + return carEntity; +} + +/****************************************************************************************************/ + +void CreateGlass(const char[] model, char[] targetName, bool startDisabled, float vPos[3], float vAng[3], char[] carName) +{ + int entity = CreateEntityByName("prop_car_glass"); + + DispatchKeyValue(entity, "targetname", targetName); + DispatchKeyValue(entity, "model", model); + DispatchKeyValue(entity, "StartDisabled", startDisabled ? "1" : "0"); + DispatchKeyValueVector(entity, "origin", vPos); + DispatchKeyValueVector(entity, "angles", vAng); + DispatchSpawn(entity); + + SetVariantString(carName); + AcceptEntityInput(entity, "SetParent", entity, entity, 0); +} + +/****************************************************************************************************/ + +void CreateSound(char[] targetName, char[] spawnFlags, char[] messageName, float vPos[3], char[] carName) +{ + int entity = CreateEntityByName("ambient_generic"); + + float newPos[3]; + newPos = vPos; + newPos[2] += 80.0; + + DispatchKeyValue(entity, "targetname", targetName); + DispatchKeyValue(entity, "spawnflags", spawnFlags); + DispatchKeyValue(entity, "message", messageName); + DispatchKeyValue(entity, "SourceEntityName", carName); + DispatchKeyValue(entity, "radius", "4000"); + DispatchKeyValueVector(entity, "origin", newPos); + DispatchSpawn(entity); + ActivateEntity(entity); // Don't work without it + + SetVariantString(carName); + AcceptEntityInput(entity, "SetParent", entity, entity, 0); +} + +/****************************************************************************************************/ + +void CreateLights(char[] lightsName, float vPos[3], float vAng[3], char[] carName) +{ + float distance[6] = {DISTANCE_FRONT, DISTANCE_SIDETURN, DISTANCE_UPFRONT, DISTANCE_BACK, DISTANCE_SIDE, DISTANCE_UPBACK}; + float newPos[3]; + float lightDistance[3]; + + newPos = vPos; + lightDistance[0] = distance[0]; + lightDistance[1] = distance[1]*-1.0; + lightDistance[2] = distance[2]; + MoveVectorvPos3D(newPos, vAng, lightDistance); // front left + CreateLight(lightsName, COLOR_YELLOWLIGHT, newPos, carName); + + newPos = vPos; + lightDistance[1] = distance[1]; + MoveVectorvPos3D(newPos, vAng, lightDistance); // front right + CreateLight(lightsName, COLOR_YELLOWLIGHT, newPos, carName); + + newPos = vPos; + lightDistance[0] = distance[3]*-1.0; + lightDistance[1] = distance[4]*-1.0; + lightDistance[2] = distance[5]; + MoveVectorvPos3D(newPos, vAng, lightDistance); // back left + CreateLight(lightsName, COLOR_REDLIGHT, newPos, carName); + + newPos = vPos; + lightDistance[1] = distance[4]; + MoveVectorvPos3D(newPos, vAng, lightDistance); // back right + CreateLight(lightsName, COLOR_REDLIGHT, newPos, carName); +} + +/****************************************************************************************************/ + +void CreateLight(char[] targetName, char[] renderColor, float vPos[3], char[] carName) +{ + int entity = CreateEntityByName("env_sprite"); + + DispatchKeyValue(entity, "targetname", targetName); + DispatchKeyValue(entity, "rendercolor", renderColor); + DispatchKeyValue(entity, "model", ALARMCAR_GLOW_SPRITE); + DispatchKeyValue(entity, "scale", "0.5"); + DispatchKeyValue(entity, "rendermode", "9"); + DispatchKeyValue(entity, "renderamt", "255"); + DispatchKeyValue(entity, "HDRColorScale", "0.7"); + DispatchKeyValue(entity, "GlowProxySize", "5"); + DispatchKeyValueVector(entity, "origin", vPos); + DispatchSpawn(entity); + + SetVariantString(carName); + AcceptEntityInput(entity, "SetParent", entity, entity, 0); +} + +/****************************************************************************************************/ + +void CreateHeadlights(char[] headlightsName, float vPos[3], float vAng[3], char[] carName) +{ + float distance[3] = {DISTANCE_FRONT, DISTANCE_SIDE, DISTANCE_UPFRONT}; + float newPos[3]; + float headlightDistance[3]; + + newPos = vPos; + headlightDistance[0] = distance[0]; + headlightDistance[1] = distance[1]*-1.0; + headlightDistance[2] = distance[2]; + MoveVectorvPos3D(newPos, vAng, headlightDistance); // front left + CreateHeadlight(headlightsName, newPos, vAng, carName); + + newPos = vPos; + headlightDistance[1] = distance[1]; + MoveVectorvPos3D(newPos, vAng, headlightDistance); // front right + CreateHeadlight(headlightsName, newPos, vAng, carName); +} + +/****************************************************************************************************/ + +void CreateHeadlight(char[] targetName, float vPos[3], float vAng[3], char[] carName) +{ + int entity = CreateEntityByName("beam_spotlight"); + + DispatchKeyValue(entity, "targetname", targetName); + DispatchKeyValue(entity, "rendercolor", COLOR_WHITELIGHT); + DispatchKeyValue(entity, "spotlightwidth", "32"); + DispatchKeyValue(entity, "spotlightlength", "256"); + DispatchKeyValue(entity, "spawnflags", "2"); + DispatchKeyValue(entity, "rendermode", "5"); + DispatchKeyValue(entity, "renderamt", "150"); + DispatchKeyValue(entity, "maxspeed", "100"); + DispatchKeyValue(entity, "HDRColorScale", "0.5"); + DispatchKeyValueVector(entity, "origin", vPos); + DispatchKeyValueVector(entity, "angles", vAng); + DispatchSpawn(entity); + + SetVariantString(carName); + AcceptEntityInput(entity, "SetParent", entity, entity, 0); +} + +/****************************************************************************************************/ + +void CreateLogicTimer(char[] targetName, char[] lightsName, char[] headlightsName, float vPos[3], char[] carName) +{ + int entity = CreateEntityByName("logic_timer"); + + DispatchKeyValue(entity, "targetname", targetName); + DispatchKeyValue(entity, "StartDisabled", "1"); + DispatchKeyValue(entity, "RefireTime", "0.75"); + + char tempString[128]; + Format(tempString, sizeof(tempString), "%s,ShowSprite,,0,-1", lightsName); + DispatchKeyValue(entity, "OnTimer", tempString); + Format(tempString, sizeof(tempString), "%s,ShowSprite,,0,-1", lightsName); + DispatchKeyValue(entity, "OnTimer", tempString); + Format(tempString, sizeof(tempString), "%s,LightOn,,0,-1", headlightsName); + DispatchKeyValue(entity, "OnTimer", tempString); + Format(tempString, sizeof(tempString), "%s,HideSprite,,0.5,-1", lightsName); + DispatchKeyValue(entity, "OnTimer", tempString); + Format(tempString, sizeof(tempString), "%s,HideSprite,,0.5,-1", lightsName); + DispatchKeyValue(entity, "OnTimer", tempString); + Format(tempString, sizeof(tempString), "%s,LightOff,,0.5,-1", headlightsName); + DispatchKeyValue(entity, "OnTimer", tempString); + DispatchKeyValueVector(entity, "origin", vPos); + DispatchSpawn(entity); + + SetVariantString(carName); + AcceptEntityInput(entity, "SetParent", entity, entity, 0); +} + +/****************************************************************************************************/ + +void CreateRemark(char[] targetName, float vPos[3], float vAng[3], char[] carName) +{ + int entity = CreateEntityByName("info_remarkable"); + + DispatchKeyValue(entity, "targetname", targetName); + DispatchKeyValue(entity, "contextsubject", "remark_caralarm"); + DispatchKeyValueVector(entity, "origin", vPos); + DispatchKeyValueVector(entity, "angles", vAng); + DispatchSpawn(entity); + + SetVariantString(carName); + AcceptEntityInput(entity, "SetParent", entity, entity, 0); +} + +/****************************************************************************************************/ + +void CreateGameEvent(char[] targetName, float vPos[3], float vAng[3], char[] carName) +{ + int entity = CreateEntityByName("info_game_event_proxy"); + + DispatchKeyValue(entity, "targetname", targetName); + DispatchKeyValue(entity, "spawnflags", "1"); + DispatchKeyValue(entity, "range", "100"); + DispatchKeyValue(entity, "event_name", "explain_disturbance"); + DispatchKeyValueVector(entity, "origin", vPos); + DispatchKeyValueVector(entity, "angles", vAng); + DispatchSpawn(entity); + + SetVariantString(carName); + AcceptEntityInput(entity, "SetParent", entity, entity, 0); +} + +/****************************************************************************************************/ + +void MoveVectorvPos3D(float vPos[3], float constvAng[3], float constDistance[3]) +{ + float vAng[3], dirFw[3], dirRi[3], dirUp[3], distance[3]; + distance = constDistance; + + vAng[0] = DegToRad(constvAng[0]); + vAng[1] = DegToRad(constvAng[1]); + vAng[2] = DegToRad(constvAng[2]); + + // roll (rotation over x) + dirFw[0] = 1.0; + dirFw[1] = 0.0; + dirFw[2] = 0.0; + dirRi[0] = 0.0; + dirRi[1] = Cosine(vAng[2]); + dirRi[2] = Sine(vAng[2])*-1; + dirUp[0] = 0.0; + dirUp[1] = Sine(vAng[2]); + dirUp[2] = Cosine(vAng[2]); + MatrixMulti(dirFw, dirRi, dirUp, distance); + + // pitch (rotation over y) + dirFw[0] = Cosine(vAng[0]); + dirFw[1] = 0.0; + dirFw[2] = Sine(vAng[0]); + dirRi[0] = 0.0; + dirRi[1] = 1.0; + dirRi[2] = 0.0; + dirUp[0] = Sine(vAng[0])*-1; + dirUp[1] = 0.0; + dirUp[2] = Cosine(vAng[0]); + MatrixMulti(dirFw, dirRi, dirUp, distance); + + // yaw (rotation over z) + dirFw[0] = Cosine(vAng[1]); + dirFw[1] = Sine(vAng[1])*-1; + dirFw[2] = 0.0; + dirRi[0] = Sine(vAng[1]); + dirRi[1] = Cosine(vAng[1]); + dirRi[2] = 0.0; + dirUp[0] = 0.0; + dirUp[1] = 0.0; + dirUp[2] = 1.0; + MatrixMulti(dirFw, dirRi, dirUp, distance); + + // addition + for (int i = 0; i < 3; i++) vPos[i] += distance[i]; +} + +/****************************************************************************************************/ + +void MatrixMulti(float matA[3], float matB[3], float matC[3], float vec[3]) +{ + float res[3]; + for (int i = 0; i < 3; i++) res[0] += matA[i]*vec[i]; + for (int i = 0; i < 3; i++) res[1] += matB[i]*vec[i]; + for (int i = 0; i < 3; i++) res[2] += matC[i]*vec[i]; + vec = res; +} + +/** +// ==================================================================================================== +:::END::: -> Source Code from DieTeetasse - [L4D1&2] Spawn Alarmcars plugin https://forums.alliedmods.net/showthread.php?t=139352 +// ==================================================================================================== +*/ \ No newline at end of file diff --git a/scripting/include/randomizer/rbuild.sp b/scripting/include/randomizer/rbuild.sp index b0fe246..2a352ce 100644 --- a/scripting/include/randomizer/rbuild.sp +++ b/scripting/include/randomizer/rbuild.sp @@ -35,8 +35,8 @@ 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)"); + menu.AddItem("new", "New Variant"); + menu.AddItem("-1", "Global Scene Variant"); JSONArray variants = view_as(g_builder.selectedSceneData.Get("variants")); JSONObject varObj; @@ -45,9 +45,9 @@ void OpenVariantsMenu(int client) { varObj = view_as(variants.Get(i)); entities = view_as(varObj.Get("entities")); if(i == g_builder.selectedVariantIndex) { - Format(display, sizeof(display), "%d entities (selected)", entities.Length); + Format(display, sizeof(display), "#%d - %d entities (✔)", i, entities.Length); } else { - Format(display, sizeof(display), "%d entities", entities.Length); + Format(display, sizeof(display), "#%d - %d entities", i, entities.Length); } IntToString(i, id, sizeof(id)); menu.AddItem(id, display); diff --git a/scripting/l4d2_editor.sp b/scripting/l4d2_editor.sp index 3ce8848..43aea98 100644 --- a/scripting/l4d2_editor.sp +++ b/scripting/l4d2_editor.sp @@ -24,6 +24,8 @@ TopMenu g_topMenu; char g_currentMap[64]; +ConVar enabledBlacklist; + //int g_markedMode #include @@ -80,6 +82,8 @@ public void OnPluginStart() { LoadTranslations("common.phrases"); HookEvent("player_spawn", Event_PlayerSpawn); + enabledBlacklist = CreateConVar("editor_denylist", "7", "The lists to check, add bits together.\n1 = classnames\n2 = models\n4 = targetnames", FCVAR_NONE, true, 0.0); + RegAdminCmd("sm_mkwall", Command_MakeWall, ADMFLAG_CUSTOM2); RegAdminCmd("sm_edit", Command_Editor, ADMFLAG_CUSTOM2); RegAdminCmd("sm_wall", Command_Editor, ADMFLAG_CUSTOM2); @@ -489,13 +493,15 @@ char FORBIDDEN_MODELS[MAX_FORBIDDEN_MODELS][] = { 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++) { - if(StrEqual(FORBIDDEN_CLASSNAMES[i], buffer)) { - return false; + if(enabledBlacklist.IntValue & 1) { + GetEntityClassname(entity, buffer, sizeof(buffer)); + for(int i = 0; i < MAX_FORBIDDEN_CLASSNAMES; i++) { + if(StrEqual(FORBIDDEN_CLASSNAMES[i], buffer)) { + return false; + } } } - if(StrContains(buffer, "prop_") > -1) { + if(enabledBlacklist.IntValue & 2) { GetEntPropString(entity, Prop_Data, "m_ModelName", buffer, sizeof(buffer)); for(int i = 0; i < MAX_FORBIDDEN_MODELS; i++) { if(StrEqual(FORBIDDEN_MODELS[i], buffer)) { @@ -503,9 +509,11 @@ bool CheckBlacklist(int entity) { } } } - GetEntPropString(entity, Prop_Data, "m_iName", buffer, sizeof(buffer)); - if(StrEqual(buffer, "l4d2_randomizer")) { - return false; + if(enabledBlacklist.IntValue & 4) { + GetEntPropString(entity, Prop_Data, "m_iName", buffer, sizeof(buffer)); + if(StrContains(buffer, "randomizer") > -1) { + return false; + } } return true; } diff --git a/scripting/l4d2_randomizer.sp b/scripting/l4d2_randomizer.sp index 636c60a..868bfda 100644 --- a/scripting/l4d2_randomizer.sp +++ b/scripting/l4d2_randomizer.sp @@ -22,9 +22,9 @@ int g_iLaserIndex; #if defined DEBUG_BLOCKERS #include #endif -#define ENT_PROP_NAME "l4d2_randomizer" -#define ENT_ENV_NAME "l4d2_randomizer" -#define ENT_BLOCKER_NAME "l4d2_randomizer" +#define ENT_PROP_NAME "randomizer" +#define ENT_ENV_NAME "randomizer" +#define ENT_BLOCKER_NAME "randomizer" #include #define MAX_SCENE_NAME_LENGTH 32 @@ -100,6 +100,7 @@ enum struct BuilderData { } #include +#include public Plugin myinfo = { @@ -116,24 +117,40 @@ public void OnPluginStart() { SetFailState("This plugin is for L4D/L4D2 only."); } + HookEvent("round_start_post_nav", Event_RoundStartPosNav); + 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"); + HookEvent("player_first_spawn", Event_PlayerFirstSpawn); + g_MapData.activeScenes = new ArrayList(sizeof(ActiveSceneData)); } +void Event_PlayerFirstSpawn(Event event, const char[] name ,bool dontBroadcast) { + int client = GetClientOfUserId(event.GetInt("userid")); + if(GetUserFlagBits(client) & ADMFLAG_CHAT) { + // If enabled but no map loaded: + if(cvarEnabled.BoolValue && g_MapData.scenes == null) + PrintToChat(client, "Randomizer Note: This map has no randomizer support at the moment."); + } +} + +void Event_RoundStartPosNav(Event event, const char[] name ,bool dontBroadcast) { + if(cvarEnabled.BoolValue) + CreateTimer(5.0, Timer_Run); +} // TODO: on round start public void OnMapStart() { g_iLaserIndex = PrecacheModel("materials/sprites/laserbeam.vmt", true); GetCurrentMap(currentMap, sizeof(currentMap)); - if(cvarEnabled.BoolValue) - CreateTimer(5.0, Timer_Run); } + public void OnMapEnd() { g_builder.Cleanup(); Cleanup(); @@ -196,7 +213,7 @@ public Action Command_CycleRandom(int client, int args) { if(client > 0) PrintCenterText(client, "Cycled flags=%d", flags); } else { - ReplyToCommand(client, "Active Scenes:"); + ReplyToCommand(client, "Active Scenes (%d/%d):", g_MapData.activeScenes.Length, g_MapData.scenes.Length); ActiveSceneData scene; for(int i = 0; i < g_MapData.activeScenes.Length; i++) { g_MapData.activeScenes.GetArray(i, scene); @@ -284,7 +301,7 @@ Action Command_RandomizerBuild(int client, int args) { } 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); + ReplyToCommand(client, "No map data loaded 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); @@ -358,10 +375,10 @@ JSONObject ExportEntity(int entity, ExportType exportType = Export_Model) { GetEntPropVector(entity, Prop_Send, "m_angRotation", angles); GetEntPropVector(entity, Prop_Send, "m_vecMaxs", size); - char model[128]; + char classname[128], model[128]; JSONObject entityData = new JSONObject(); - GetEntityClassname(entity, model, sizeof(model)); - if(StrContains(model, "prop_") == -1) { + GetEntityClassname(entity, classname, sizeof(classname)); + if(StrContains(classname, "prop_") == -1) { entityData.Set("scale", VecToArray(size)); } if(exportType == Export_HammerId) { @@ -376,6 +393,7 @@ JSONObject ExportEntity(int entity, ExportType exportType = Export_Model) { entityData.SetString("model", model); } else { GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model)); + entityData.SetString("type", classname); entityData.SetString("model", model); } entityData.Set("origin", VecToArray(origin)); @@ -567,17 +585,18 @@ enum InputType { enum struct VariantInputData { char name[MAX_INPUTS_CLASSNAME_LENGTH]; InputType type; - char input[32]; + char input[64]; void Trigger() { int entity = -1; switch(this.type) { case Input_Classname: { - entity = FindEntityByClassname(entity, this.name); - this._trigger(entity); + while((entity = FindEntityByClassname(entity, this.name)) != INVALID_ENT_REFERENCE) { + this._trigger(entity); + } } case Input_Targetname: { - char targetname[32]; + char targetname[64]; while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE) { GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname)); if(StrEqual(targetname, this.name)) { @@ -613,14 +632,19 @@ enum struct VariantInputData { AcceptEntityInput(entity, "Close"); AcceptEntityInput(entity, "Lock"); AcceptEntityInput(entity, "SetUnbreakable"); - }else { + } else { char cmd[32]; // Split input "a b" to a with variant "b" int len = SplitString(this.input, " ", cmd, sizeof(cmd)); - if(len > -1) SetVariantString(this.input[len]); + if(len > -1) { + SetVariantString(this.input[len]); + AcceptEntityInput(entity, cmd); + Debug("_trigger(%d): %s (v=%s)", entity, cmd, this.input[len]); + } else { + Debug("_trigger(%d): %s", entity, this.input); + AcceptEntityInput(entity, this.input); + } - Debug("_trigger(%d): %s (v=%s)", entity, this.input, cmd); - AcceptEntityInput(entity, this.input); } } } @@ -858,7 +882,7 @@ void loadChoice(SceneData scene, JSONObject choiceData, JSONArray extraEntities) // Parses entities and loads to choice.entities loadChoiceEntity(choice.entities, view_as(extraEntities.Get(i))); } - delete extraEntities; + // delete extraEntities; } // Load all inputs if(choiceData.HasKey("inputs")) { @@ -874,6 +898,7 @@ void loadChoice(SceneData scene, JSONObject choiceData, JSONArray extraEntities) for(int i = 0; i < scenes.Length; i++) { scenes.GetString(i, sceneId, sizeof(sceneId)); choice.forcedScenes.PushString(sceneId); + Debug("scene %s: require %s", scene.name, sceneId); } delete scenes; } @@ -882,6 +907,7 @@ void loadChoice(SceneData scene, JSONObject choiceData, JSONArray extraEntities) void loadChoiceInput(ArrayList list, JSONObject inputData) { VariantInputData input; + input.type = Input_Classname; // Check classname -> targetname -> hammerid if(!inputData.GetString("classname", input.name, sizeof(input.name))) { if(inputData.GetString("targetname", input.name, sizeof(input.name))) { @@ -936,10 +962,10 @@ void loadChoiceEntity(ArrayList list, JSONObject entityData) { entityData.GetString("model", entity.model, sizeof(entity.model)); if(!entityData.GetString("type", entity.type, sizeof(entity.type))) { entity.type = "prop_dynamic"; - } else if(entity.type[0] == '_') { + } /*else if(entity.type[0] == '_') { LogError("Invalid custom entity type \"%s\"", entity.type); return; - } + }*/ GetVector(entityData, "origin", entity.origin); GetVector(entityData, "angles", entity.angles); GetVector(entityData, "scale", entity.scale); @@ -1013,24 +1039,35 @@ void selectScenes(int flags = 0) { // Traverse active scenes, loading any other scene it requires (via .force_scenes) ActiveSceneData aScene; SceneVariantData choice; + char sceneId[64]; + // list of scenes that will need to be forced if not already: 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); + // Load scene from active scene entry + if(!g_MapData.scenesKv.GetArray(aScene.name, scene, sizeof(scene))) { + // can't find scene, ignore + continue; + } + if(aScene.variantIndex < scene.variants.Length) { + 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); + } } } } + if(forcedScenes.Length > 0) { + Debug("Loading %d forced scenes", forcedScenes.Length); + } // 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++) { + for(int j = 0; j < g_MapData.activeScenes.Length; j++) { g_MapData.activeScenes.GetArray(j, aScene); if(StrEqual(aScene.name, key)) { isSceneAlreadyLoaded = true; @@ -1077,7 +1114,6 @@ void selectScene(SceneData scene, int flags) { } } } - Debug("Total choices: %d", choices.Length); if(flags & view_as(FLAG_ALL_VARIANTS)) { delete choices; } else if(choices.Length > 0) { @@ -1118,7 +1154,7 @@ void spawnEntity(VariantEntityData entity) { CreateEnvBlockerScaled(entity.type, entity.origin, entity.scale); } else if(StrEqual(entity.type, "infodecal")) { CreateDecal(entity.model, entity.origin); - } else if(StrContains(entity.type, "prop_") == 0) { + } else if(StrContains(entity.type, "prop_") == 0 || StrEqual(entity.type, "prop_fuel_barrel")) { if(entity.model[0] == '\0') { LogError("Missing model for entity with type \"%s\"", entity.type); return; @@ -1165,6 +1201,8 @@ void spawnEntity(VariantEntityData entity) { } if(!found) Debug("Warn: Could not find entity (classname=%s)", entity.model); + } else if(StrContains(entity.type, "_car") != -1) { + SpawnCar(entity); } else { LogError("Unknown entity type \"%s\"", entity.type); } @@ -1201,6 +1239,17 @@ void Cleanup() { } delete g_MapData.lumpEdits; + // Cleanup all alarm car entities: + int entity = -1; + char targetname[128]; + while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE) { + GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname)); + if(StrContains(targetname, "randomizer_car") != -1) { + RemoveEntity(entity); + } + } + // TODO: delete car alarms + DeleteCustomEnts(); g_MapData.activeScenes.Clear(); } \ No newline at end of file