PDA

View Full Version : [Solved] [L4D2] Witch target override in better way?


HarryPotter
12-27-2020, 22:00
As the title says, I need a function like this


//entitiy: witch
//client: a target that witch will chase
//return true if succeed, return false if can't change witch target

bool WitchAttackTarget( int entity, int client)


Change target when the witch incapacitates or kills victim,
I know some plugins already did this before, but there are still some problems.

Example:
1. [L4D & L4D2] Evil Witch (https://forums.alliedmods.net/showthread.php?t=167077)
Spawns a new witch and give a hurt point. I think that is not good.

2. [L4D2] Relentless Witch (https://forums.alliedmods.net/showthread.php?t=175040)
He uses signature "@_ZN8Infected15OnHitByVomitJarEP20CBaseCombat Character" on witch, but the director will call a horde.

Edit:
Thanks BHaType, xZk, cravenge and silvers, I write code here (https://forums.alliedmods.net/showpost.php?p=2732048&postcount=9) for myself

Marttt
12-28-2020, 00:23
Is not exactly what you asked...

Maybe you can force the target with CommandABot

Usually, we use that for bots (clients) (Scavenge Bots use this, I think).

I have never seen a plugin to common infected/witch.

Didn't test but here are some examples.

https://gist.github.com/Rectus/8d7604f350c824e45ec5ce378ed09264 (steamworkshop source (https://steamcommunity.com/sharedfiles/filedetails/?id=510573647))

https://github.com/search?q=commandabot+extension%3Asp&type=code

BHaType
12-28-2020, 03:27
My old practices, they work but as far as I remember the server will crash if you change the target when the witch is not scared yet

You can also literally change the target to any entity and patch the WitchAttack::IsValidEnemy function so the witch can run after anyone and not just survivors

#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>

static const int byte[] =
{
0x1CC8, 0x1C, 0x8,
0x10, 0x10
};

public void OnPluginStart()
{
RegConsoleCmd("sm_insult", sm_insult);
}

public Action sm_insult ( int client, int args )
{
int client = GetClientAimTarget(client);

if ( client == -1 )
return;

int witch = MaxClients + 1, target;

while ( (witch = FindEntityByClassname(witch, "witch")) && IsValidEntity(witch) )
{
target = GetCurrentWitchTarget(witch);

if ( target == -1 ) /* So the witch had lost her target or didn't have one yet */
continue;

PrintToChatAll("Current target is %i changing to %i", target, client);
ChangeWitchTarget(witch, client);
}
}

int GetCurrentWitchTarget (int witch)
{
Address behavior = GetEntityAddress(witch);

for ( int i; i < sizeof byte; i++ )
{
if ( behavior == Address_Null )
return -1;

behavior = view_as<Address>(LoadFromAddress(behavior + view_as<Address>(byte[i]), NumberType_Int32));
}

for ( int i = 1; i <= MaxClients; i++ )
{
if ( !IsValidEntity(i) )
continue;

if ( LoadFromAddress(GetEntityAsRef(i), NumberType_Int32) == LoadFromAddress(behavior + view_as<Address>(0x34), NumberType_Int32) )
return i;
}

return -1;
}

bool ChangeWitchTarget (int witch, int target)
{
Address behavior = GetEntityAddress(witch);

for ( int i; i < sizeof byte; i++ )
{
if ( behavior == Address_Null )
return false;

behavior = view_as<Address>(LoadFromAddress(behavior + view_as<Address>(byte[i]), NumberType_Int32));
}

StoreToAddress(behavior + view_as<Address>(0x34), LoadFromAddress(GetEntityAsRef(target), NumberType_Int32), NumberType_Int32);
StoreToAddress(behavior + view_as<Address>(56), 8, NumberType_Int32);

return true;
}

Address GetEntityAsRef (int entity)
{
static Handle call;

if ( !call )
{
StartPrepSDKCall(SDKCall_Entity);
PrepSDKCall_SetAddress(view_as<Address>(LoadFromAddress(view_as<Address>(LoadFromAddress(GetEntityAddress(entity), NumberType_Int32) + 8), NumberType_Int32)));
PrepSDKCall_SetReturnInfo(SDKType_PlainOldDat a, SDKPass_Plain);
call = EndPrepSDKCall();
}

return view_as<Address>(SDKCall(call, entity));
}

Note:
If this still works then I might try to make a more advanced version and this is for windows only

HarryPotter
12-28-2020, 04:27
I will give a try and report

HarryPotter
12-28-2020, 07:45
Note:
If this still works then I might try to make a more advanced version and this is for windows only

I just tested,
Everything works fine in windows server,
no crash, no wired behavior.

I just have a little wish,
It could be better if we can force witch to attack another target again even after witch had lost her target or killed survivor already.

larrybrains
12-29-2020, 22:47
If this still works then I might try to make a more advanced version and this is for windows only

Would love to see a Linux version of this.

xZk
01-02-2021, 20:15
ago I was looking for something like that, and maybe this can be useful when the witch loses her objective, but I think it only works for survivors :/:

stock void WitchChangeTarget(int witch, int target)
{
//PrintToChatAll("attacking target %N", target);
if(GetEntProp(witch, Prop_Send, "m_bIsBurning") == 1){
ExtinguishEntity(witch);
SDKHooks_TakeDamage(witch, target, target, 0.0, DMG_BURN);
}else{
int anim = GetEntProp(witch, Prop_Send, "m_nSequence");
SDKHooks_TakeDamage(witch, target, target, 0.0, DMG_BURN);
SetEntProp(witch, Prop_Send, "m_nSequence", anim);
SetVariantFloat(0.0);
AcceptEntityInput(witch, "IgniteLifetime");
//ExtinguishEntity(witch);// no works
SetEntProp(witch, Prop_Send, "m_bIsBurning", 0);
int ent = GetEntPropEnt(witch, Prop_Data, "m_hMoveChild");
if(IsValidEnt(ent)){
char classname[32];
GetEntityClassname(ent, classname, sizeof(classname));
if(strcmp(classname, "entityflame") == 0){
SDKHook(ent, SDKHook_SetTransmit, SetTransmit_Fire);
}
}
}
}

public Action SetTransmit_Fire(int entity, int client)
{
return Plugin_Handled;
}

HarryPotter
01-04-2021, 21:30
ago I was looking for something like that, and maybe this can be useful when the witch loses her objective, but I think it only works for survivors :/:
Working for survivors is enough to me, I will give a try

HarryPotter
01-10-2021, 07:21
Thanks BHaType, xZk, cravenge and silvers, I write a script for myself

Witch target override Improved version 1.8 [2022/11/14]
Change target when the witch incapacitates or kills victim + witchs auto follow survivors

Feature
* Witch is allowed to chase another target after she incapacitates a survivor.
* Witch is allowed to chase another target after she kills a survivor.
* Witch will not follow survivor if there is a wall between witch and survivor.
* Witch will not follow survivor if survivor standing on the higher place.
* Witch burns for a set amount of time and die. ("z_witch_burn_time" is 15 seconds)

apply to:
L4D1/2


-Source Code Download-
Latest version always here (https://github.com/fbef0102/L4D1_2-Plugins/tree/master/witch_target_override)

cravenge
01-10-2021, 08:47
You might improve the method on completely removing the fire from the Witch. You could take a look at the Bots Trigger Witch plugin by Silvers.

HarryPotter
01-10-2021, 09:47
You might improve the method on completely removing the fire from the Witch. You could take a look at the Bots Trigger Witch plugin by Silvers.

Nice, I have already added. thanks.

larrybrains
03-13-2021, 12:57
Nice, I have already added. thanks.

Is there a way to do this while accounting for the witch burn time?

The way fire works on the witch is that she burns for a set amount of time (z_witch_burn_time 15 seconds = default) before she dies from the fire, regardless of how much health she has. If you light her on fire with full health, she will burn for 15 seconds, or if you light her on fire with 10% health, she will also burn for 15 seconds before she dies.

So when you extinguish her and then re-light her, the burn timer starts over, and you could have a witch burning for 30 or 45 seconds without her dying.

EDIT: You can of course still kill her by shooting/meleeing her while she is on fire before the burn timer runs out, but survivor players often assume that the witch will burn to death and will sometimes just run backwards and let her burn while she chases without trying to shoot/melee her.

NoroHime
01-22-2022, 01:39
some problem here...overriding witch wouldnt be knock back, like propane tank etc.
and they always spawn as standing, when turn to "unrelentless witch" problems gone

HarryPotter
01-22-2022, 14:36
some problem here...overriding witch wouldnt be knock back, like propane tank etc.
and they always spawn as standing, when turn to "unrelentless witch" problems gone

Really? I test this plugin alone and witch can be knock back by propane tank, awp, explosive ammo even if witch is following survivor.
Check v1.4 version and try again.

Is there a way to do this while accounting for the witch burn time?


Witch target override Improved version 1.4 [2022/1/23] (https://forums.alliedmods.net/showpost.php?p=2732048&postcount=9)
-Improve and optimize code
-Witch will not follow survivor if there is a wall between witch and survivor.
-Witch will not follow survivor if survivor standing on the higher place.
-Witch burns for a set amount of time and die. (z_witch_burn_time 15 seconds = default)


// If 1, the burning witch restarts and recalculates burning time if she is allowed to chased another target. (0=after witch burns for a set amount of time z_witch_burn_time, she dies from the fire)
witch_target_override_recalculate_burn_time "0"

thewintersoldier97
05-03-2022, 01:13
...

Hi Harry, nice plugin. I just have a question, what does
witch_target_override_incap_health_add "400"
and
witch_target_override_kill_health_add "1000"
actually do? Does those cvar "heal" the witch when they incap/kill a survivors or does it stand for value of the witch's health which where she allowed to chase another survivors?

HarryPotter
05-03-2022, 21:00
Hi Harry, nice plugin. I just have a question, what does
witch_target_override_incap_health_add "400"
and
witch_target_override_kill_health_add "1000"
actually do?
Heal Witch Health, witch hp > 1000 possible

thewintersoldier97
05-04-2022, 02:44
Heal Witch Health, witch hp > 1000 possible

Got it, thank you :D

larrybrains
06-01-2022, 23:09
Witch target override Improved version 1.5 [2022/2/13]

Latest version always here (https://github.com/fbef0102/L4D1_2-Plugins/tree/master/witch_target_override)

I was looking at your code and it looks like this plugin also unsticks the witch when she gets stuck or am I mistaken?

HarryPotter
06-01-2022, 23:33
I was looking at your code and it looks like this plugin also unsticks the witch when she gets stuck or am I mistaken?
I did not unstick witch, just make her walk and move