mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-06 21:33:20 +00:00
Added l4d2_ai_minigun && l4d2_avoid_minigun
This commit is contained in:
parent
c5dc4d66f3
commit
92c2dd33ba
5 changed files with 413 additions and 0 deletions
13
README.md
13
README.md
|
@ -11,6 +11,8 @@ All my sourcemod plugins... shitty probably
|
|||
* [L4D2FFKickProtection](#L4D2FFKickProtection)
|
||||
* [l4d2_ff_test](#l4d2_ff_test)
|
||||
* [CSGOTroll](#CSGOTroll)
|
||||
* [l4d2_avoid_minigun](#l4d2_avoid_minigun)
|
||||
* [l4d2_ai_minigun](#l4d2_ai_minigun)
|
||||
|
||||
## Descriptions
|
||||
### csgo-knifehp
|
||||
|
@ -89,3 +91,14 @@ Another joke plugin, with it configured, a victim will have a % chance their sho
|
|||
* `troll_shot_fail_percentage <0.0-1.0>` - percentage float (0.0 to 1.0) chance that victims' shots fail
|
||||
* `troll_targets <ids>` - comma separated list of steamid64 targets (ex: STEAM_0:0:75141700)
|
||||
* `troll_shot_mode <0/1>` - 0 -> ALL Weapons, 1 -> AWP
|
||||
|
||||
### l4d2_avoid_minigun
|
||||
Makes the bots avoid standing infront/on top of the player that is using a minigun. It checks every 2.0 seconds if they are infront, then tells them to move to behind you. There is no configuration, all automatic.
|
||||
|
||||
### l4d2_ai_minigun
|
||||
Allows you to spawn a holdout type bot. This bot will spawn with a minigun, like louis in the passing. Supports all 8 characters.
|
||||
Technically it is louis using minigun with a model change, but it works fine.
|
||||
|
||||
Note: Sometimes bill model fails to spawn in, and is just invisible.
|
||||
* **Commands:**
|
||||
* `sm_spawn_minigun_bot <model name>` - Spawns the ai bot infront of wherever you are looking. Can also use numbers (0-7).
|
BIN
plugins/l4d2_ai_minigun.smx
Normal file
BIN
plugins/l4d2_ai_minigun.smx
Normal file
Binary file not shown.
BIN
plugins/l4d2_avoid_minigun.smx
Normal file
BIN
plugins/l4d2_avoid_minigun.smx
Normal file
Binary file not shown.
284
scripting/l4d2_ai_minigun.sp
Normal file
284
scripting/l4d2_ai_minigun.sp
Normal file
|
@ -0,0 +1,284 @@
|
|||
#pragma semicolon 1
|
||||
#pragma newdecls required
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#define PLUGIN_NAME "l4d2 ai minigun"
|
||||
#define PLUGIN_DESCRIPTION ""
|
||||
#define PLUGIN_AUTHOR "jackzmc"
|
||||
#define PLUGIN_VERSION "1.0"
|
||||
#define PLUGIN_URL ""
|
||||
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
//#include <sdkhooks>
|
||||
|
||||
#define MODEL_MINIGUN "models/w_models/weapons/w_minigun.mdl"
|
||||
#define MODEL_FRANCIS "models/survivors/survivor_biker.mdl"
|
||||
#define MODEL_LOUIS "models/survivors/survivor_manager.mdl"
|
||||
#define MODEL_ZOEY "models/survivors/survivor_teenangst.mdl"
|
||||
#define MODEL_BILL "models/survivors/survivor_namvet.mdl"
|
||||
#define MODEL_NICK "models/survivors/survivor_gambler.mdl"
|
||||
#define MODEL_COACH "models/survivors/survivor_coach.mdl"
|
||||
#define MODEL_ELLIS "models/survivors/survivor_mechanic.mdl"
|
||||
#define MODEL_ROCHELLE "models/survivors/survivor_producer.mdl"
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = PLUGIN_NAME,
|
||||
author = PLUGIN_AUTHOR,
|
||||
description = PLUGIN_DESCRIPTION,
|
||||
version = PLUGIN_VERSION,
|
||||
url = PLUGIN_URL
|
||||
};
|
||||
|
||||
int g_iSurvivors[MAXPLAYERS+1], g_iLastSpawnClient;
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
EngineVersion g_Game = GetEngineVersion();
|
||||
if(g_Game != Engine_Left4Dead && g_Game != Engine_Left4Dead2)
|
||||
{
|
||||
SetFailState("This plugin is for L4D/L4D2 only.");
|
||||
}
|
||||
|
||||
RegAdminCmd("sm_spawn_minigun_bot", Command_SpawnAIBot, ADMFLAG_ROOT);
|
||||
}
|
||||
public void OnMapStart() {
|
||||
PrecacheModel(MODEL_MINIGUN);
|
||||
PrecacheModel(MODEL_LOUIS);
|
||||
PrecacheModel(MODEL_ZOEY);
|
||||
PrecacheModel(MODEL_BILL);
|
||||
PrecacheModel(MODEL_FRANCIS);
|
||||
}
|
||||
public void OnClientPutInServer(int client) {
|
||||
if( g_iLastSpawnClient == -1)
|
||||
{
|
||||
g_iSurvivors[client] = GetClientUserId(client);
|
||||
g_iLastSpawnClient = GetClientUserId(client);
|
||||
}
|
||||
}
|
||||
public Action Command_SpawnAIBot(int client, int args) {
|
||||
char arg1[16];
|
||||
if(args > 0) {
|
||||
GetCmdArg(1, arg1, sizeof(arg1));
|
||||
char model[64];
|
||||
FindModelFromString(arg1, model, sizeof(model));
|
||||
|
||||
//get ground:
|
||||
float vPos[3], vAng[3];
|
||||
if(!GetGround(client, vPos, vAng)) {
|
||||
LogError("Failed to find ground for survivor");
|
||||
ReplyToCommand(client, "Could not find a suitable ground location to spawn survivor.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
//make sure spawns a little above
|
||||
vPos[2] += 1.0;
|
||||
|
||||
if(!SpawnSurvivor(vPos, vAng, model, true)) {
|
||||
ReplyToCommand(client, "Failed to spawn survivor.");
|
||||
}
|
||||
}else{
|
||||
ReplyToCommand(client, "Usage: sm_spawn_minigun_bot <4=Bill, 5=Zoey, 6=Francis, 7=Louis>");
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
bool SpawnSurvivor(const float vPos[3], const float vAng[3], const char[] model, bool spawn_minigun) {
|
||||
int entity = CreateEntityByName("info_l4d1_survivor_spawn");
|
||||
if( entity == -1 ) {
|
||||
LogError("Failed to create \"info_l4d1_survivor_spawn\"");
|
||||
return false;
|
||||
}
|
||||
//set character type (7 = Louis)
|
||||
DispatchKeyValue(entity, "character", "7");
|
||||
//on spawn, to kill spawner
|
||||
//AcceptEntityInput(entity, "AddOutput");
|
||||
AcceptEntityInput(entity, "Kill");
|
||||
|
||||
//teleport spawner to valid spot & spawn it
|
||||
TeleportEntity(entity, vPos, vAng, NULL_VECTOR);
|
||||
DispatchSpawn(entity);
|
||||
|
||||
//Tell spawner to spawn survivor
|
||||
g_iLastSpawnClient = -1;
|
||||
AvoidCharacter(7, true);
|
||||
AcceptEntityInput(entity, "SpawnSurvivor");
|
||||
AvoidCharacter(7, false);
|
||||
|
||||
//remove reference to last spawn id
|
||||
int bot_user_id = g_iLastSpawnClient, bot_client_id;
|
||||
g_iLastSpawnClient = -1;
|
||||
if( bot_user_id <= 0 || (bot_client_id = GetClientOfUserId(bot_user_id)) <= 0 )
|
||||
{
|
||||
LogError("Failed to match survivor, did they not spawn? [%d/%d]", bot_user_id, bot_client_id);
|
||||
return false;
|
||||
}
|
||||
SetClientName(bot_client_id, "MinigunBot");
|
||||
TeleportEntity(bot_client_id, vPos, NULL_VECTOR, NULL_VECTOR);
|
||||
|
||||
if(spawn_minigun && !SpawnMinigun(vAng, vPos)) {
|
||||
LogError("Failed to spawn minigun for client #%d", bot_client_id);
|
||||
KickClient(bot_client_id, "AIMinigun:MinigunSpawnFailure");
|
||||
return false;
|
||||
}
|
||||
TeleportEntity(bot_client_id, vPos, NULL_VECTOR, NULL_VECTOR);
|
||||
SetEntityModel(bot_client_id, model);
|
||||
CreateTimer(1.5, TimerMove, bot_user_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
stock bool FindModelFromString(const char str[16], char[] model, int modelStrSize) {
|
||||
int possibleNumber = StringToInt(str, 10);
|
||||
if(modelStrSize == 1 && possibleNumber <= 7 && possibleNumber >= 0) {
|
||||
switch(possibleNumber) {
|
||||
case 0: {
|
||||
strcopy(model, modelStrSize, MODEL_NICK);
|
||||
} case 1: {
|
||||
strcopy(model, modelStrSize, MODEL_ELLIS);
|
||||
} case 2: {
|
||||
strcopy(model, modelStrSize, MODEL_COACH);
|
||||
} case 3: {
|
||||
strcopy(model, modelStrSize, MODEL_ROCHELLE);
|
||||
} case 4: {
|
||||
strcopy(model, modelStrSize, MODEL_BILL);
|
||||
} case 5: {
|
||||
strcopy(model, modelStrSize, MODEL_ZOEY);
|
||||
} case 6: {
|
||||
strcopy(model, modelStrSize, MODEL_FRANCIS);
|
||||
} case 7: {
|
||||
strcopy(model, modelStrSize, MODEL_LOUIS);
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}else{
|
||||
if(possibleNumber == 0) {
|
||||
//try to parse str
|
||||
if(StrEqual(str, "bill", false)) {
|
||||
strcopy(model, modelStrSize, MODEL_BILL);
|
||||
}else if(StrEqual(str, "zoey", false)) {
|
||||
strcopy(model, modelStrSize, MODEL_ZOEY);
|
||||
}else if(StrEqual(str, "francis", false)) {
|
||||
strcopy(model, modelStrSize, MODEL_FRANCIS);
|
||||
}else if(StrEqual(str, "louis", false)) {
|
||||
strcopy(model, modelStrSize, MODEL_LOUIS);
|
||||
}else if(StrEqual(str, "nick", false)) {
|
||||
strcopy(model, modelStrSize, MODEL_NICK);
|
||||
}else if(StrEqual(str, "ellis", false)) {
|
||||
strcopy(model, modelStrSize, MODEL_ELLIS);
|
||||
}else if(StrEqual(str, "rochelle", false)) {
|
||||
strcopy(model, modelStrSize, MODEL_ROCHELLE);
|
||||
}else if(StrEqual(str, "coach", false)) {
|
||||
strcopy(model, modelStrSize, MODEL_COACH);
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpawnMinigun(const float vAng[3], const float vPos[3]) {
|
||||
float vDir[3], newPos[3];
|
||||
GetAngleVectors(vAng, vDir, NULL_VECTOR, NULL_VECTOR);
|
||||
vDir[0] = vPos[0] + (vDir[0] * 50);
|
||||
vDir[1] = vPos[1] + (vDir[1] * 50);
|
||||
vDir[2] = vPos[2] + 20.0;
|
||||
newPos = vDir;
|
||||
newPos[2] -= 40.0;
|
||||
|
||||
Handle trace = TR_TraceRayFilterEx(vDir, newPos, MASK_SHOT, RayType_EndPoint, TraceFilter);
|
||||
if(TR_DidHit(trace)) {
|
||||
TR_GetEndPosition(vDir, trace);
|
||||
|
||||
int minigun = CreateEntityByName("prop_mounted_machine_gun");
|
||||
minigun = EntIndexToEntRef(minigun);
|
||||
SetEntityModel(minigun, MODEL_MINIGUN);
|
||||
DispatchKeyValue(minigun, "targetname", "louis_holdout");
|
||||
DispatchKeyValueFloat(minigun, "MaxPitch", 360.00);
|
||||
DispatchKeyValueFloat(minigun, "MinPitch", -360.00);
|
||||
DispatchKeyValueFloat(minigun, "MaxYaw", 90.00);
|
||||
newPos[2] += 0.1;
|
||||
TeleportEntity(minigun, vDir, vAng, NULL_VECTOR);
|
||||
DispatchSpawn(minigun);
|
||||
delete trace;
|
||||
return true;
|
||||
}else{
|
||||
LogError("Spawn minigun trace failure");
|
||||
delete trace;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stock bool TraceFilter(int entity, int contentsMask) {
|
||||
if( entity <= MaxClients )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
stock bool GetGround(int client, float[3] vPos, float[3] vAng) {
|
||||
GetClientAbsOrigin(client, vPos);
|
||||
vAng = vPos;
|
||||
vAng[2] += 5.0;
|
||||
vPos[2] -= 500.0;
|
||||
|
||||
Handle trace = TR_TraceRayFilterEx(vAng, vPos, MASK_SHOT, RayType_EndPoint, TraceFilter);
|
||||
if(!TR_DidHit(trace))
|
||||
{
|
||||
delete trace;
|
||||
return false;
|
||||
}
|
||||
TR_GetEndPosition(vPos, trace);
|
||||
delete trace;
|
||||
|
||||
GetClientAbsAngles(client, vAng);
|
||||
return true;
|
||||
}
|
||||
|
||||
g_iAvoidChar[MAXPLAYERS+1] = {-1,...};
|
||||
void AvoidCharacter(int type, bool avoid)
|
||||
{
|
||||
for( int i = 1; i <= MaxClients; i++ )
|
||||
{
|
||||
if( IsClientInGame(i) && (GetClientTeam(i) == 2 || GetClientTeam(i) == 4) )
|
||||
{
|
||||
if( avoid )
|
||||
{
|
||||
// Save character type
|
||||
g_iAvoidChar[i] = GetEntProp(i, Prop_Send, "m_survivorCharacter");
|
||||
int set;
|
||||
switch( type )
|
||||
{
|
||||
case 4: set = 3; // Bill
|
||||
case 5: set = 2; // Zoey
|
||||
case 7: set = 1; // Francis
|
||||
case 6: set = 0; // Louis
|
||||
}
|
||||
SetEntProp(i, Prop_Send, "m_survivorCharacter", set);
|
||||
} else {
|
||||
// Restore player type
|
||||
if( g_iAvoidChar[i] != -1 )
|
||||
{
|
||||
SetEntProp(i, Prop_Send, "m_survivorCharacter", g_iAvoidChar[i]);
|
||||
g_iAvoidChar[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !avoid )
|
||||
{
|
||||
for( int i = 1; i <= MAXPLAYERS; i++ )
|
||||
g_iAvoidChar[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
Action TimerMove(Handle timer, any client) {
|
||||
if((client = GetClientOfUserId(client))) {
|
||||
//PrintToServer("client %d %N",client,client);
|
||||
SetEntityMoveType(client, MOVETYPE_NONE);
|
||||
TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, view_as<float>({ 0.0, 0.0, 0.0 }));
|
||||
}
|
||||
}
|
116
scripting/l4d2_avoid_minigun.sp
Normal file
116
scripting/l4d2_avoid_minigun.sp
Normal file
|
@ -0,0 +1,116 @@
|
|||
#pragma semicolon 1
|
||||
#pragma newdecls required
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#define PLUGIN_NAME "L4D2 AI Avoid Minigun"
|
||||
#define PLUGIN_DESCRIPTION "Makes the ai avoid being infront of a minigun in use"
|
||||
#define PLUGIN_AUTHOR "jackzmc"
|
||||
#define PLUGIN_VERSION "1.0"
|
||||
#define PLUGIN_URL ""
|
||||
#define PI 3.14159265358
|
||||
#define UNITS_SPAWN -120.0
|
||||
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
//#include <sdkhooks>
|
||||
|
||||
#define MODEL_MINIGUN "models/w_models/weapons/w_minigun.mdl"
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = PLUGIN_NAME,
|
||||
author = PLUGIN_AUTHOR,
|
||||
description = PLUGIN_DESCRIPTION,
|
||||
version = PLUGIN_VERSION,
|
||||
url = PLUGIN_URL
|
||||
};
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
EngineVersion g_Game = GetEngineVersion();
|
||||
if(g_Game != Engine_Left4Dead && g_Game != Engine_Left4Dead2)
|
||||
{
|
||||
SetFailState("This plugin is for L4D/L4D2 only.");
|
||||
}
|
||||
CreateTimer(2.0, CheckTimer, _, TIMER_REPEAT);
|
||||
}
|
||||
|
||||
public Action CheckTimer(Handle timer) {
|
||||
for(int i = 1; i < MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) && GetClientTeam(i) == 2) {
|
||||
bool usingMinigun = GetEntProp(i, Prop_Send, "m_usingMountedGun", 1) == 1;
|
||||
bool usingMountedWeapon = GetEntProp(i, Prop_Send, "m_usingMountedWeapon", 1) == 1;
|
||||
|
||||
if(usingMinigun || usingMountedWeapon) {
|
||||
float pos[3], ang[3], finalPos[3], checkPos[3];
|
||||
GetClientAbsOrigin(i, pos);
|
||||
GetClientEyeAngles(i, ang);
|
||||
GetHorizontalPositionFromOrigin(pos, ang, 40.0, checkPos);
|
||||
GetHorizontalPositionFromOrigin(pos, ang, UNITS_SPAWN, finalPos);
|
||||
|
||||
for(int bot = 1; bot < MaxClients; bot++) {
|
||||
if(IsClientConnected(bot) && IsFakeClient(bot) && GetClientTeam(bot) == 2) {
|
||||
float botPos[3];
|
||||
GetClientAbsOrigin(bot, botPos);
|
||||
|
||||
float center_distance = GetVectorDistance(checkPos, botPos);
|
||||
|
||||
if(center_distance <= 70) {
|
||||
//PrintHintTextToAll("Bot: %N | d=%f | d2=%f | Vector(%.2f,%.2f,%.2f)", bot, distance, center_distance, finalPos[0], finalPos[1], finalPos[2]);
|
||||
//todo: only teleport once?
|
||||
//TeleportEntity(bot, finalPos, NULL_VECTOR, NULL_VECTOR);
|
||||
L4D2_RunScript("CommandABot({cmd=1,bot=GetPlayerFromUserID(%i),pos=Vector(%f,%f,%f)})", GetClientUserId(bot), finalPos[0], finalPos[1], finalPos[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stock void GetHorizontalPositionFromOrigin(const float pos[3], const float ang[3], float units, float finalPosition[3]) {
|
||||
float theta = DegToRad(ang[1]);
|
||||
finalPosition[0] = units * Cosine(theta) + pos[0];
|
||||
finalPosition[1] = units * Sine(theta) + pos[1];
|
||||
finalPosition[2] = pos[2];
|
||||
}
|
||||
stock void GetHorizontalPositionFromClient(int client, float units, float finalPosition[3]) {
|
||||
float pos[3], ang[3];
|
||||
GetClientEyeAngles(client, ang);
|
||||
GetClientAbsOrigin(client, pos);
|
||||
|
||||
float theta = DegToRad(ang[1]);
|
||||
pos[0] += -150 * Cosine(theta);
|
||||
pos[1] += -150 * Sine(theta);
|
||||
finalPosition = pos;
|
||||
}
|
||||
|
||||
stock void L4D2_RunScript(const char[] sCode, any ...) {
|
||||
static int iScriptLogic = INVALID_ENT_REFERENCE;
|
||||
if(iScriptLogic == INVALID_ENT_REFERENCE || !IsValidEntity(iScriptLogic)) {
|
||||
iScriptLogic = EntIndexToEntRef(CreateEntityByName("logic_script"));
|
||||
if(iScriptLogic == INVALID_ENT_REFERENCE|| !IsValidEntity(iScriptLogic))
|
||||
SetFailState("Could not create 'logic_script'");
|
||||
|
||||
DispatchSpawn(iScriptLogic);
|
||||
}
|
||||
|
||||
static char sBuffer[512];
|
||||
VFormat(sBuffer, sizeof(sBuffer), sCode, 2);
|
||||
|
||||
SetVariantString(sBuffer);
|
||||
AcceptEntityInput(iScriptLogic, "RunScriptCode");
|
||||
}
|
||||
stock void ShowDelayedHintToAll(const char[] format, any ...) {
|
||||
char buffer[254];
|
||||
VFormat(buffer, sizeof(buffer), format, 2);
|
||||
static int hintInt = 0;
|
||||
if(hintInt >= 7) {
|
||||
PrintHintTextToAll("%s",buffer);
|
||||
hintInt = 0;
|
||||
}
|
||||
hintInt++;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue