Page 1 of 3

Avoid teleporting of Queens

Posted: Tue Jun 12, 2018 9:38 pm
by Barbie
I tried to avoid teleporting Queens. The only parts where a Queen goes into State Teleporting are the following state functions in the code of Queen:

Code: Select all

state TacticalMove
{
ignores SeePlayer, HearNoise;

	function PickDestination(bool bNoCharge)
	{
		if ( FRand() < 0.26 )
			GotoState('Teleporting');
		else
			Super.PickDestination(bNoCharge);
	}
}

state Hunting
{
ignores EnemyNotVisible; 

	function PickDestination()
	{
		GotoState('Teleporting');
	}
}
I changed that to

Code: Select all

state TacticalMove
{
ignores SeePlayer, HearNoise;

	function PickDestination(bool bNoCharge)
	{
		if ((FRand() < 0.26) && bHaveQueenDests)
			GotoState('Teleporting');
		else
			Super.PickDestination(bNoCharge);
	}
}


state Hunting
{
ignores EnemyNotVisible;

	function PickDestination()
	{
		if (bHaveQueenDests)
			GotoState('Teleporting');
		else
			Super.PickDestination();
	}
}
and although bHaveQueenDests is false, the Queen can teleport.

Any hints?

Re: Avoid teleporting of Queens

Posted: Tue Jun 12, 2018 10:31 pm
by MrLoathsome
Change these lines: GotoState('Teleporting');

To: GotoState('Wandering'); or GotoState('Roaming'); or GotoState('Attacking');* *maybe
(maybe lose the check on bHaveQueenDests)
Let us know what happens...

Re: Avoid teleporting of Queens

Posted: Tue Jun 12, 2018 11:19 pm
by Barbie
MrLoathsome wrote:Change these lines: GotoState('Teleporting');
Same result: Queens are still teleporting.

They stop teleporting, if I use empty state functions for PickDestination(). So State Teleporting it must be entered in Super.PickDestination().

Re: Avoid teleporting of Queens

Posted: Wed Jun 13, 2018 6:19 am
by sektor2111
In some package NsMonster, queen was disturbing. What I did step by step I cannot entirely recall right now but definitely I recall that I was looking everywhere about string
GoToState('Teleporting'), but EVERYWHERE in code Including Hunting. Definitely when Queen doesn't see enemy it should stay the hell in place else it does dumb shit with that encroachment. As I could see so far, even in "nice" XC deal a map still went broken (counted queens have vaporized) so I disabled the fix (using that Configurable UScript part of XCGE - posted by me) and I left the "original" code to run but I think next days worth a small revision here. I could see if Queen is busy with an enemy not visible and camping (Bot Stackout or such), it will be invulnerable and visible closer enemies will exhaust ammo firing weaponry USELESS. This stupidity will be removed, I might think at checking pawns around would have a benefit from time time and getting a new enemy rather than stupidly teleporting awaiting enemy to show up - probably this code won't be net compatible so maybe the first solution is more suitable here... unless a sort of new XC_Stuff like that DripGenerator and XC_Titans will have compatibility and code will be executed from a better Queen, for sure it will be required to be permanent, even for maps which don't have queens but factories spawning them - there also will be a master tweak, slowing to 1 QUEEN per row, capturing potential counters and capping values. There is still work to do here - maps patching or common code...

Presumed fixing situation:
Queen wants a QueenDest closer to visible pawn enemy. If there is None, then Stackout as other monster if cannot see enemy else it will be RANGEDATTACK. If did not see any enemy for a while (LastSeenTime or such), Enemy - None (OldEnemy - None) WhatToDoNext - DONE. By dropping queen here and there is not an answer, if Queen is a guardian will leave guarding spot and chances to go back are probably NONE due to it's size and "fascinating" paths which mapper is doing, so excuse me but Teleporting to a PathNode is not the solution here and neither dropping it behind a door/wall.
Another "fix":
Leave all code and Do NOT Ignore TakeDamage in state Teleporting - has to be well tested...

Edit: A bit concerning what is in state Teleporting

Code: Select all

ignores TakeDamage, SeePlayer, EnemyNotVisible, HearNoise, KilledBy, Bump, HitWall, HeadZoneChange, FootZoneChange, ZoneChange, Falling, WarnTarget, Died;
Ignoring Died and KilledBy ? In my opinion This state is not finished. I'm not surprised to see that it breaks events then... I think is removed skipping the most important things...

Re: Avoid teleporting of Queens

Posted: Sun Jun 17, 2018 2:27 am
by Barbie
Meanwhile I have found out why my sub classed Queen teleports: I defined it as

Code: Select all

class QueenSB expands Queen;
and then I call

Code: Select all

Super.PickDestination(bNoCharge);
what executes the original Queen's code - including teleporting. Maybe I was too tired when I did that... :roll:


But the next problem follows: now I want to skip original Queen's state function and execute Queen's parent state function instead. The code for this should be

Code: Select all

Super(ScriptedPawn).PickDestination(bNoCharge)
and I did that with QueenSB in state "TacticalMove" (see full code below). But the compiler says Unknown function 'PickDestination' in Class UnrealShare.ScriptedPawn - but ScriptedPawn has a function "PickDestination" in state "TacticalMove". How to tell the compiler my wish?

Appendix:
Full code

Code: Select all

class QueenSB expands Queen;

var() bool bHaveQueenDests;

state TacticalMove
{
ignores SeePlayer, HearNoise;

	function PickDestination(bool bNoCharge)
	{
		if ((FRand() < 0.26) && bHaveQueenDests)
			GotoState('Teleporting');
// This does not compile:
		else
			Super(ScriptedPawn).PickDestination(bNoCharge);
	}
}

Re: Avoid teleporting of Queens

Posted: Sun Jun 17, 2018 4:33 am
by MrLoathsome
Copy ALL the Queen source into your QueenSB.Queen class.
Have your QueenSB.Queen Class extend ScriptedPawn.

Then change PickDestination as needed.

Re: Avoid teleporting of Queens

Posted: Sun Jun 17, 2018 7:37 am
by sektor2111
Barbie wrote:But the next problem follows: now I want to skip original Queen's state function and execute Queen's parent state function instead.
That was/is the same problem from "Humane" repeating Trooper code (and spawning 2 weapons not one) because of Super.CrapFunction() called. All these are things doable >>
CASE1) as follows:
- USE ALL code from ScriptedPawn and never call Super in here. This Super in such case will not prevent original Queen to mess the new class... and will prevent ruining mutators using "IsA('Queen')" magic code... :|
Case2)
- rewrite Queen from UnrealI and conform package with the stock from year 2000 whatever UT436, and... forget new bHasQueenDest variable. It won't help you. Recommending in state Hunting to put a random or a visual condition WITHOUT any new bool. Else, return Hunting to some attack if QueenDest from NavigationPointList is None so to speak there is no such destination available (because mapper was paying for stuff and did not have money for it :loool: ), also preventing mutators to mess with another "Queen". Here you can adjust those stupid collision values as well probably speeding up collision processing - lol, EPIC...

Edit:
Reason. Some stock different Queen which I have to test intensive according to code bellow:

Code: Select all

//=============================================================================
// Queen.
//=============================================================================
class Queen expands ScriptedPawn;

#exec MESH IMPORT MESH=SkQueen ANIVFILE=MODELS\queen_a.3D DATAFILE=MODELS\queen_d.3D X=0 Y=0 Z=0
#exec MESH ORIGIN MESH=SkQueen X=0 Y=-130 Z=80 YAW=64 ROLL=-64

#exec MESH SEQUENCE MESH=Skqueen SEQ=All		STARTFRAME=0	NUMFRAMES=171
#exec MESH SEQUENCE MESH=Skqueen SEQ=ThreeHit	STARTFRAME=0	NUMFRAMES=18	RATE=15  Group=Attack 
#exec MESH SEQUENCE MESH=Skqueen SEQ=Claw		STARTFRAME=18   NUMFRAMES=10	RATE=15  Group=Attack
#exec MESH SEQUENCE MESH=Skqueen SEQ=Gouge		STARTFRAME=28   NUMFRAMES=13	RATE=15  Group=Attack
#exec MESH SEQUENCE MESH=Skqueen SEQ=Jump		STARTFRAME=41   NUMFRAMES=1
#exec MESH SEQUENCE MESH=Skqueen SEQ=Land		STARTFRAME=42   NUMFRAMES=1
#exec MESH SEQUENCE MESH=Skqueen SEQ=Meditate	STARTFRAME=43   NUMFRAMES=8		RATE=6
#exec MESH SEQUENCE MESH=Skqueen SEQ=OutCold	STARTFRAME=51   NUMFRAMES=21	RATE=15
#exec MESH SEQUENCE MESH=Skqueen SEQ=TakeHit	STARTFRAME=52   NUMFRAMES=1
#exec MESH SEQUENCE MESH=Skqueen SEQ=Run		STARTFRAME=72   NUMFRAMES=10	RATE=17
#exec MESH SEQUENCE MESH=Skqueen SEQ=Scream		STARTFRAME=82   NUMFRAMES=23	RATE=15
#exec MESH SEQUENCE MESH=Skqueen SEQ=Fighter	STARTFRAME=105  NUMFRAMES=1
#exec MESH SEQUENCE MESH=Skqueen SEQ=Shoot1		STARTFRAME=105  NUMFRAMES=23	RATE=15  Group=Attack
#exec MESH SEQUENCE MESH=Skqueen SEQ=Stab		STARTFRAME=128  NUMFRAMES=8		RATE=15  Group=Attack
#exec MESH SEQUENCE MESH=Skqueen SEQ=Walk		STARTFRAME=136  NUMFRAMES=15	RATE=17
#exec MESH SEQUENCE MESH=Skqueen SEQ=Shield		STARTFRAME=151  NUMFRAMES=20	RATE=25


#exec TEXTURE IMPORT NAME=JQueen1 FILE=MODELS\queen.PCX GROUP=Skins
#exec MESHMAP SCALE MESHMAP=Skqueen X=0.22 Y=0.22 Z=0.44
#exec MESHMAP SETTEXTURE MESHMAP=Skqueen NUM=1 TEXTURE=Jqueen1 

#exec MESH NOTIFY MESH=Skqueen SEQ=Shoot1 TIME=0.167 FUNCTION=SpawnShot
#exec MESH NOTIFY MESH=Skqueen SEQ=Shoot1 TIME=0.255 FUNCTION=SpawnShot
#exec MESH NOTIFY MESH=Skqueen SEQ=Shoot1 TIME=0.344 FUNCTION=SpawnShot
#exec MESH NOTIFY MESH=Skqueen SEQ=Shoot1 TIME=0.433 FUNCTION=SpawnShot
#exec MESH NOTIFY MESH=Skqueen SEQ=OutCold TIME=0.60 FUNCTION=LandThump
#exec MESH NOTIFY MESH=Skqueen SEQ=Claw   TIME=0.5   FUNCTION=ClawDamageTarget
#exec MESH NOTIFY MESH=Skqueen SEQ=Gouge  TIME=0.4   FUNCTION=ClawDamageTarget
#exec MESH NOTIFY MESH=Skqueen SEQ=Stab   TIME=0.33  FUNCTION=StabDamageTarget
#exec MESH NOTIFY MESH=Skqueen SEQ=Walk   TIME=0.26  FUNCTION=FootStep
#exec MESH NOTIFY MESH=Skqueen SEQ=Walk   TIME=0.76  FUNCTION=FootStep
#exec MESH NOTIFY MESH=Skqueen SEQ=Run    TIME=0.25  FUNCTION=FootStep
#exec MESH NOTIFY MESH=Skqueen SEQ=Run    TIME=0.75  FUNCTION=FootStep
#exec MESH NOTIFY MESH=Skqueen SEQ=Shield TIME=0.75  FUNCTION=SpawnShield

#exec AUDIO IMPORT FILE="Sounds\Queen\claw1Q.WAV" NAME="claw1Q" GROUP="Queen"
#exec AUDIO IMPORT FILE="Sounds\Queen\shoot1Q.WAV" NAME="shoot1Q" GROUP="Queen"
#exec AUDIO IMPORT FILE="Sounds\Queen\yell1Q.WAV" NAME="yell1Q" GROUP="Queen"
#exec AUDIO IMPORT FILE="Sounds\Queen\yell2Q.WAV" NAME="yell2Q" GROUP="Queen"
#exec AUDIO IMPORT FILE="Sounds\Queen\yell3Q.WAV" NAME="yell3Q" GROUP="Queen"
#exec AUDIO IMPORT FILE="Sounds\Queen\stab1Q.WAV" NAME="stab1Q" GROUP="Queen"
#exec AUDIO IMPORT FILE="Sounds\Queen\outcoldQ.WAV" NAME="outcoldQ" GROUP="Queen"
#exec AUDIO IMPORT FILE="Sounds\Queen\nearby2Q.WAV" NAME="nearby2Q" GROUP="Queen"
#exec AUDIO IMPORT FILE="Sounds\Queen\amb1Q.WAV" NAME="amb1Q" GROUP="Queen"
#exec AUDIO IMPORT FILE="Sounds\Titan\step1a.WAV" NAME="step1t" GROUP="Titan"
#exec AUDIO IMPORT FILE="..\UnrealShare\Sounds\Generic\teleport1.WAV" NAME="Teleport1" GROUP="Generic"

//Queen variables;
var() int ClawDamage,
	StabDamage;
var() name ScreamEvent;

var byte row;
var(Sounds) sound footstepSound;
var(Sounds) sound ScreamSound;
var(Sounds) sound stab;
var(Sounds) sound shoot;
var(Sounds) sound claw;

var bool	bJustScreamed;
var bool	bEndFootStep;
var QueenShield Shield;
var vector TelepDest;

function PostBeginPlay()
{
	Super.PostBeginPlay();
	ProjectileSpeed = 1200 + 100 * Skill;
	GroundSpeed = GroundSpeed * (1 + 0.1 * Skill);
}

event bool EncroachingOn( actor Other )
{
	return Super(Pawn).EncroachingOn(Other);
	return false;
}

function TryToDuck(vector duckDir, bool bReversed)
{
	if ( (Shield != None) || (AnimSequence == 'Shield') )
		return;

	PlayAnim('Shield', 1.0, 0.1);
	bCrouching = true;
	GotoState('RangedAttack', 'Challenge');
}

function SpawnShield()
{
	Shield = Spawn(class'QueenShield',,,Location + 150 * Vector(Rotation)); 
	Shield.SetBase(self);
}

function eAttitude AttitudeToCreature(Pawn Other)
{
	if ( Other == None || Other.bDeleteMe )
		return ATTITUDE_Friendly;

	if ( Other.IsA('Skaarj') )
	{
		if ( Other.IsA('SkaarjBerserker') )
			return ATTITUDE_Hate;
		else
			return ATTITUDE_Friendly;
	}
	else if ( Other.IsA('Pupae') )
		return ATTITUDE_Friendly;
	else if ( Other.IsA('Nali') )
		return ATTITUDE_Hate;
	else
		return ATTITUDE_Ignore;
}

function ThrowOther(Pawn Other)
{
	local float dist, shake;
	local PlayerPawn aPlayer;
	local vector Momentum;

	if ( Other.mass > 500 || Other == None || Other.bDeleteMe || Other.Health <= 0 )
		return;

	aPlayer = PlayerPawn(Other);				
	if (aPlayer == None)
	{	
		if (Other.Physics != PHYS_Walking)
			return;
		dist = VSize(Location - Other.Location);
		if (dist > 500)
			return;
	}
	else
	{
		dist = VSize(Location - Other.Location);
		shake = FMax(500, 1500 - dist);
		if ( dist > 1500 )
			return;
		aPlayer.ShakeView( FMax(0, 0.35 - dist/20000), shake, 0.015 * shake);
		if ( (Other.Physics != PHYS_Walking) || (dist > 1500) )
			return;
	}
	
	Momentum = -0.5 * Other.Velocity + 100 * Normal(Other.Location - Location);
	Momentum.Z =  7000000.0/((0.5 * dist + 500) * Other.Mass);
	Other.AddVelocity(Momentum);
}

function FootStep()
{
	bEndFootstep = false;
	PlaySound(FootstepSound, SLOT_Interact, 8);
}

function Scream()
{
	local actor A;
	local pawn Thrown;

	if (ScreamEvent != '')
		foreach AllActors( class 'Actor', A, ScreamEvent )
			A.Trigger( Self, Instigator );

	PlaySound(ScreamSound, SLOT_Talk, 2 * TransientSoundVolume);
	PlaySound(ScreamSound, SLOT_None, 2 * TransientSoundVolume);
/*
	Stopping this stupidity
*/
//	PlaySound(ScreamSound, SLOT_None, 2 * TransientSoundVolume);
//	PlaySound(ScreamSound, SLOT_None, 2 * TransientSoundVolume);
	PlayAnim('Scream');
	bJustScreamed = true;
}

function PlayWaiting()
{
	local float decision;
	local float animspeed;
	
	if (bEndFootStep)
		FootStep();
	decision = FRand();
	animspeed = 0.2 + 0.5 * FRand();
	LoopAnim('Meditate', animspeed);
}

function PlayChallenge()
{
	if (bEndFootStep)
		FootStep();
	if ( IsAnimating() && (AnimSequence == 'Shield') )
		return;
	Scream();
}

function TweenToFighter(float tweentime)
{
	bEndFootStep = ( ((AnimSequence == 'Walk') || (AnimSequence == 'Run')) && (AnimFrame > 0.1) );   
	TweenAnim('Fighter', tweentime);
}

function TweenToRunning(float tweentime)
{
	if ( (AnimSequence != 'Run') || !bAnimLoop )
		TweenAnim('Run', tweentime);
}

function TweenToWalking(float tweentime)
{
	TweenAnim('Walk', tweentime);
}

function TweenToWaiting(float tweentime)
{
	TweenAnim('Meditate', tweentime);
}

function TweenToPatrolStop(float tweentime)
{
	TweenAnim('Meditate', tweentime);
}

function PlayRunning()
{
	LoopAnim('Run', -1.0/GroundSpeed,, 0.8);
}

function PlayWalking()
{
	LoopAnim('Walk', -1.0/GroundSpeed,, 0.8);
}

function PlayThreatening()
{
	DesiredSpeed = 0.0;

	if ( FRand() < 0.75)
		PlayAnim('Meditate', 0.4 + 0.6 * FRand(), 0.3);
	else 
	{
		TweenAnim('Fighter', 0.3);
		PlayThreateningSound();
	}
}

function PlayTurning()
{
	if (bEndFootStep)
		FootStep();
	DesiredSpeed = 0.0;
	TweenAnim('Run', 0.4);
}

function PlayDying(name DamageType, vector HitLocation)
{
	PlayAnim('OutCold', 0.7, 0.1);
	PlaySound(Die, SLOT_Talk);	
}

function PlayTakeHit(float tweentime, vector HitLoc, int Damage)
{
	TweenAnim('TakeHit', tweentime);
}

function SpawnShot()
{
	local vector X,Y,Z, projStart;

	GetAxes(Rotation,X,Y,Z);
	
	if (row == 0)
		MakeNoise(1.0);
	
	projStart = Location + 1 * CollisionRadius * X + ( 0.7 - 0.2 * row) * CollisionHeight * Z + 0.2 * CollisionRadius * Y;
	spawn(RangedProjectile ,self,'',projStart,AdjustAim(ProjectileSpeed, projStart, 400 * (4 - row)/(3.5-skill), false, bWarnTarget));

	projStart = Location + 1 * CollisionRadius * X + ( 0.7 - 0.2 * row) * CollisionHeight * Z - 0.2 * CollisionRadius * Y;
	spawn(RangedProjectile ,self,'',projStart,AdjustAim(ProjectileSpeed, projStart, 400 * (4 - row)/(3.5-skill), true, bWarnTarget));
	row++;
}

function PlayVictoryDance()
{
	if (bEndFootStep)
		FootStep();
	DesiredSpeed = 0.0;
	PlayAnim('ThreeHit', 0.7, 0.15); //gib the enemy here!
	PlaySound(Threaten, SLOT_Talk);		
}

function ClawDamageTarget()
{
	if ( Target != None )
		if ( MeleeDamageTarget(ClawDamage, (50000.0 * (Normal(Target.Location - Location)))) )
			PlaySound(Claw, SLOT_Interact);
}

function StabDamageTarget()
{
	local vector X,Y,Z;

	if ( Target != None )
	{
		GetAxes(Rotation,X,Y,Z);
		if ( MeleeDamageTarget(StabDamage, (15000.0 * ( Y + vect(0,0,1)))) )
			PlaySound(Stab, SLOT_Interact);
	}
}

function PlayMeleeAttack()
{
	local float decision;

	if (bEndFootStep)
		FootStep();
	decision = FRand();
	if (decision < 0.4)
	{
		PlaySound(Stab, SLOT_Interact);
 		PlayAnim('Stab');
 	}
	else if (decision < 0.7)
	{
		PlaySound(Claw, SLOT_Interact);
		PlayAnim('Claw');
	} 
	else 
	{
		PlaySound(Claw, SLOT_Interact);
		PlayAnim('Gouge');
	}
}

function TweenToFalling()
{
	TweenAnim('Jump', 0.2);
}

function PlayInAir()
{
	TweenAnim('Jump', 0.5);
}

function PlayLanded(float impactVel)
{
	local Pawn Thrown;

	TweenAnim('Land', 0.1);

	//throw all nearby creatures, and play sound
	Thrown = Level.PawnList;
	While ( Thrown != None )
	{
		ThrowOther(Thrown);
		Thrown = Thrown.nextPawn;
	}
}

function PlayRangedAttack()
{
	if (Target != None)
	{
		if (bEndFootStep)
			FootStep();

		if ( !bJustScreamed && (FRand() < 0.15) )
			Scream();
		else if ( (Shield != None) && (FRand() < 0.5)
			&& (((Target.Location - Location) Dot (Shield.Location - Location)) > 0) )
			Scream();
		else
		{
			if ( Shield != None )
				Shield.Destroy();
			row = 0;
			bJustScreamed = false;
			PlayAnim('Shoot1'); 
			PlaySound(Shoot, SLOT_Interact);			
		}
	}
}

state TacticalMove
{
ignores SeePlayer, HearNoise;

	function PickDestination(bool bNoCharge)
	{
		if ( FRand() < 0.26 )
			GotoState('Teleporting');
		else
			Super.PickDestination(bNoCharge);
	}
}		
		
state Hunting
{
ignores EnemyNotVisible; 

	function PickDestination()
	{
		if ( (Enemy == Self) || (Enemy == None) || (Enemy.Health <= 0) || (Enemy.bDeleteMe) )
		{
			WhatToDoNext('','');
			return;
		}
		if ( LineOfSightTo(Enemy) )
		{
			GotoState('RangedAttack','Challenge');
			return;
		}
		if ( FRand() < 0.2 )
			GotoState('Teleporting');
		else
			Super.PickDestination();
	}
}


State Teleporting
{
ignores TakeDamage, SeePlayer, EnemyNotVisible, HearNoise, /*KilledBy,*/ Bump, HitWall, HeadZoneChange, FootZoneChange, ZoneChange, Falling, WarnTarget /*, Died*/;

	function Tick(float DeltaTime)
	{
		local int NewFatness; 
		local rotator EnemyRot;

		if ( TelepDest == Location || ( FRand() > 0.5 && Enemy != None && !LineOfSightTo(Enemy) ) ) //50% chances to NOT go retarded or do nothing if destination is the same location - NO QueenDest HERE
		{
			GoToState('RangedAttack','Challenge');
			return;
		}
/*
To check: checking if dealing with Style is helpful - OR NOT
*/
		if ( Style == STY_Translucent )
		{
			ScaleGlow -= 3 * DeltaTime;
			if ( ScaleGlow < 0.3 )
			{
				Spawn(class'QueenTeleportEffect',,, TelepDest);
				Spawn(class'QueenTeleportLight',,, TelepDest);
				EnemyRot = rotator(Enemy.Location - Location);
				EnemyRot.Pitch = 0;
				if ( TelepDest != Location ) //No need to teleport in the same location - only if it's not already there, geniuses !
					SetLocation(TelepDest);
				setRotation(EnemyRot);
				PlaySound(sound'Teleport1', SLOT_Interface);
				GotoState('Attacking');
			}
			return;
		}
		else
		{
			NewFatness = fatness - 100 * DeltaTime;
			if ( NewFatness < 80 )
			{
				bUnlit = true;
				ScaleGlow = 2.0;
				Style = STY_Translucent;
			}
		}

		fatness = Clamp(NewFatness, 0, 255);
	}

	function ChooseDestination()
	{
		local NavigationPoint N;
		local vector ViewPoint, HitLocation, HitNormal, Best;
		local actor HitActor;
		local float rating, newrating;

		N = Level.NavigationPointList;
		Best = Location;
		rating = 0;

		while ( N != None )
		{
			if ( N.IsA('QueenDest') ) // rate it
			{
				newrating = 0;
				if ( Best == Location )
					Best = N.Location;
				ViewPoint = N.Location + EyeHeight * vect(0,0,1);
				HitActor = Trace(HitLocation, HitNormal, Enemy.Location, ViewPoint, false);
				if ( HitActor == None )
					newrating = 20000;

				newrating = newrating - VSize(N.Location - Enemy.Location) + 1000 * FRand()
							+ 4 * VSize(N.Location - Location);
				if ( N.Location.Z > Enemy.Location.Z )
					newrating += 1000;
				
				if ( newrating > rating )
				{
					rating = newrating;
					Best = N.Location;
				}
			}

			N = N.nextNavigationPoint;
		}

		TelepDest = Best;
	}

	function BeginState()
	{
		Acceleration = Vect(0,0,0);
		ChooseDestination();
	}

	function EndState()
	{
		bUnlit = false;
		Style = STY_Normal;
		ScaleGlow = 1.0;
		fatness = Default.fatness;
	}
}
Eh, we do not have to remove teleporting, we have to LOVE teleporting when is done different... :agree1: .
Firsts results:
- will not telefrag nobody - that was really stupid;
- might teleport as a combat feature not as a default insane lousy habit;
- assumption for now: I think won't break events as was doing before.

Re: Avoid teleporting of Queens

Posted: Sun Jun 17, 2018 10:57 pm
by EvilGrins
For whatever it's worth, I find by not going anywhere near the Queens or just not shooting at them... they don't teleport.
:mrgreen: :highfive: :wtf:

Re: Avoid teleporting of Queens

Posted: Mon Jun 18, 2018 6:10 am
by sektor2111
EvilGrins wrote:For whatever it's worth, I find by not going anywhere near the Queens or just not shooting at them... they don't teleport.
For not ending such a map worth to not vote it but another one. I don't get what exactly do you mean. If you don't shoot them and are counted maybe killing them using a telekinetic influence or letting them to die starved would help, right ? Barbie has asked a solution not an useless post. We have to solve these problems once forever rather than only making noise and annoying those which might want to see a solution for this case as well.
All I have to say in this moment is that MA-Queens randomly going broken as others with multiple queens around won't do headaches, thy won't teleport in a "busy" spot and they use teleporting more random. The same good state in 2MuchHP, going to see Demons][ with those 2 Queens, but I think I have relevant results, there is nothing lost at removing that stupid encroachment. As for mods based on some sort of Queen Telefragging Titans - a supposed replacement (a la Lucky), Good Luck with them... exist indeed a solution (or more) for such case but I'm not bother to dig in other yard.
PS:
And, Yes, MH admins, a MH server will not be the best deal with default stock files or out of replacements... any super duper MH is not helping that much when is about multiple queens under counter.
The main note:
Stock Queen from Unreal... has a string " the Queen", it's not like " a Pupae". Logic explanation: in Level you might see more that one Pupae it's just "a Pupae". But when we speak about Queen it will be " the Queen" supposed to be unique not for "spammy servers" which people are finding cool as broken as they are. For such a server it's required some work for polishing a bit the action, default files only are not an answer, are broken stuff.

Re: Avoid teleporting of Queens

Posted: Mon Jun 18, 2018 3:13 pm
by RocketJedi
I have seen the queen in an endless teleport loop on our servers on a few occasions. Sometimes they can't be killed unless a huge nuke is used. shooting them with non ultra powerful weapons tends to be useless. I would like to test a possible fix when available

Re: Avoid teleporting of Queens

Posted: Mon Jun 18, 2018 4:22 pm
by MrLoathsome
I think I posted the solution.

If you name your Package QueenSB and the class Queen, i.e. "QueenSB.Queen" to summon/spawn,
I believe it will pass the IsA('Queen') check.

(Note, haven't actually tested that....)

Re: Avoid teleporting of Queens

Posted: Mon Jun 18, 2018 5:00 pm
by sektor2111
MrLoathsome wrote:If you name your Package QueenSB and the class Queen, i.e. "QueenSB.Queen" to summon/spawn,
I believe it will pass the IsA('Queen') check.
I'm sure will work as do works other things like IsA('MonsterHunt') used in a newer trigger able to finish a non default MH game, it only does a check to a 'Name', so it should be good if answer is replacing default Queen... with a class having the same Name but I hope compiler to not cry, at least in my DeathMatchPlus did not happened and was "class DeathMatchPlus expands BotPack.DeathMatchPlus" compiled without issues but taking in account to manage well those "Super" calls else everything goes down-hill executing parent borked stuff.

@Qwerty
You can speak with your coder(s), probably Mar can handle this, the modified Queen which I posted is fully compatible with default Queen, so to speak client won't be skating trying to match new class because it uses default things, nothing new, just wrapping, so it can be conformed with default UT client with no issues - I HAVE such a Queen at this moment (I must backup server again - reminder for me) and it does look tens times better - NOT RECOMMEND posting any of such package in public, these aren't for players and if a new package is being posted claimed server-fix, jesters are mindlessly loading them in 2 seconds and ACE will kick them out, to not forget potential errors which won't be a good thing. Each admin might fix these how wants, Queen which I posted is not a default rule, also fixing in this way it's a suggestion not a must be.

Re: Avoid teleporting of Queens

Posted: Wed Jun 27, 2018 2:02 am
by Barbie
Got my new Queen running and checked:
QueenSB

Code: Select all

class QueenSB expands Queen;

/******************************************************************************
Changes to UnrealI.Queen:
1) Queens spawned via factory do not telefrag other queens (based on function
   EncroachingOn())
2) Queens try to teleport only once if there is no QueenDest (based on variable
   "QueenDestHave").
3) Queens do not telefrag other pawns on QueenDests.
4) *ProjectileSpeed* is used now.

Hint: if you use CheckReplacement() to exchange the Queens, you should also
exchange "Prototype" in factories.
******************************************************************************/


var enum EQueenDestHave {
  QDH_Yes, QDH_No, QDH_Unchecked
} QueenDestHave;


event bool EncroachingOn( actor Other ) {
	if ( (Other.Brush != None) || (Brush(Other) != None) || Queen(Other) != None)
		return true;

	return false;
}




function bool RadiusActorHave(Actor A, class<actor> SearchClass, float Radius) {
local Actor Result;

	foreach A.RadiusActors(SearchClass, Result, Radius, A.Location)
		return true;
	return false;
}



function PostBeginPlay() {
local float PreProjectileSpeed;

	PreProjectileSpeed = ProjectileSpeed;
	Super.PostBeginPlay();
	// same as in Queen.PostBeginPlay(), except using *ProjectileSpeed* now instead of "1200":
	ProjectileSpeed = PreProjectileSpeed + 100 * Skill;
}



state TacticalMove
{
ignores SeePlayer, HearNoise;

	function PickDestination(bool bNoCharge)
	{
	// copied all variables from ScriptedPawn.TacticalMove.PickDestination(), because "Super(ScriptedPawn).PickDestination(bNoCharge)" does not compile
	local vector pickdir, enemydir, enemyPart, Y, minDest;
	local actor HitActor;
	local vector HitLocation, HitNormal, collSpec;
	local float Aggression, enemydist, minDist, strafeSize, optDist;
	local bool success, bNoReach;

		if ((FRand() < 0.26) && QueenDestHave != QDH_No)
		{
			GotoState('Teleporting');
			Return;
		}
	// copied all remaining lines from ScriptedPawn.TacticalMove.PickDestination(), because "Super(ScriptedPawn).PickDestination(bNoCharge)" does not compile
		bChangeDir = false;
		if (Region.Zone.bWaterZone && !bCanSwim && bCanFly)
		{
			Destination = Location + 75 * (VRand() + vect(0,0,1));
			Destination.Z += 100;
			return;
		}
		if ( Enemy.Region.Zone.bWaterZone )
			bNoCharge = bNoCharge || !bCanSwim;
		else
			bNoCharge = bNoCharge || (!bCanFly && !bCanWalk);

		success = false;
		enemyDist = VSize(Location - Enemy.Location);
		Aggression = 2 * (CombatStyle + FRand()) - 1.1;
		if ( intelligence == BRAINS_Human )
		{
			if ( Enemy.bIsPlayer && (AttitudeToPlayer == ATTITUDE_Fear) && (CombatStyle > 0) )
				Aggression = Aggression - 2 - 2 * CombatStyle;
			if ( Weapon != None )
				Aggression += 2 * Weapon.SuggestAttackStyle();
			if ( Enemy.Weapon != None )
				Aggression += 2 * Enemy.Weapon.SuggestDefenseStyle();
		}

		if ( enemyDist > 1000 )
			Aggression += 1;
		if ( bIsPlayer && !bNoCharge )
			bNoCharge = ( Aggression < FRand() );

		if ( (Physics == PHYS_Walking) || (Physics == PHYS_Falling) )
		{
			if (Location.Z > Enemy.Location.Z + 140) //tactical height advantage
				Aggression = FMax(0.0, Aggression - 1.0 + CombatStyle);
			else if (Location.Z < Enemy.Location.Z - CollisionHeight) // below enemy
			{
				if ( !bNoCharge && (Intelligence > BRAINS_Reptile)
					&& (Aggression > 0) && (FRand() < 0.6) )
				{
					GotoState('Charging');
					return;
				}
				else if ( (enemyDist < 1.1 * (Enemy.Location.Z - Location.Z))
						&& !actorReachable(Enemy) )
				{
					bNoReach = (Intelligence > BRAINS_None);
					aggression = -1.5 * FRand();
				}
			}
		}

		if (!bNoCharge && (Aggression > 2 * FRand()))
		{
			if ( bNoReach && (Physics != PHYS_Falling) )
			{
				TweenToRunning(0.15);
				GotoState('Charging', 'NoReach');
			}
			else
				GotoState('Charging');
			return;
		}

		if (enemyDist > FMax(VSize(OldLocation - Enemy.OldLocation), 240))
			Aggression += 0.4 * FRand();

		enemydir = (Enemy.Location - Location)/enemyDist;
		minDist = FMin(160.0, 3*CollisionRadius);
		if ( bIsPlayer )
			optDist = 80 + FMin(EnemyDist, 250 * (FRand() + FRand()));
		else
			optDist = 50 + FMin(EnemyDist, 500 * FRand());
		Y = (enemydir Cross vect(0,0,1));
		if ( Physics == PHYS_Walking )
		{
			Y.Z = 0;
			enemydir.Z = 0;
		}
		else
			enemydir.Z = FMax(0,enemydir.Z);

		strafeSize = FMax(-0.7, FMin(0.85, (2 * Aggression * FRand() - 0.3)));
		enemyPart = enemydir * strafeSize;
		strafeSize = FMax(0.0, 1 - Abs(strafeSize));
		pickdir = strafeSize * Y;
		if ( bStrafeDir )
			pickdir *= -1;
		bStrafeDir = !bStrafeDir;
		collSpec.X = CollisionRadius;
		collSpec.Y = CollisionRadius;
		collSpec.Z = FMax(6, CollisionHeight - 18);

		minDest = Location + minDist * (pickdir + enemyPart);
		HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec);
		if (HitActor == None)
		{
			success = (Physics != PHYS_Walking);
			if ( !success )
			{
				collSpec.X = FMin(14, 0.5 * CollisionRadius);
				collSpec.Y = collSpec.X;
				HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec);
				success = (HitActor != None);
			}
			if (success)
				Destination = minDest + (pickdir + enemyPart) * optDist;
		}

		if ( !success )
		{
			collSpec.X = CollisionRadius;
			collSpec.Y = CollisionRadius;
			minDest = Location + minDist * (enemyPart - pickdir);
			HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec);
			if (HitActor == None)
			{
				success = (Physics != PHYS_Walking);
				if ( !success )
				{
					collSpec.X = FMin(14, 0.5 * CollisionRadius);
					collSpec.Y = collSpec.X;
					HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec);
					success = (HitActor != None);
				}
				if (success)
					Destination = minDest + (enemyPart - pickdir) * optDist;
			}
			else
			{
				if ( (CombatStyle <= 0) || (Enemy.bIsPlayer && (AttitudeToPlayer == ATTITUDE_Fear)) )
					enemypart = vect(0,0,0);
				else if ( (enemydir Dot enemyPart) < 0 )
					enemyPart = -1 * enemyPart;
				pickDir = Normal(enemyPart - pickdir + HitNormal);
				minDest = Location + minDist * pickDir;
				collSpec.X = CollisionRadius;
				collSpec.Y = CollisionRadius;
				HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec);
				if (HitActor == None)
				{
					success = (Physics != PHYS_Walking);
					if ( !success )
					{
						collSpec.X = FMin(14, 0.5 * CollisionRadius);
						collSpec.Y = collSpec.X;
						HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec);
						success = (HitActor != None);
					}
					if (success)
						Destination = minDest + pickDir * optDist;
				}
			}
		}

		if ( !success )
			GiveUpTactical(bNoCharge);
		else
		{
			pickDir = (Destination - Location);
			enemyDist = VSize(pickDir);
			if ( enemyDist > minDist + 2 * CollisionRadius )
			{
				pickDir = pickDir/enemyDist;
				HitActor = Trace(HitLocation, HitNormal, Destination + 2 * CollisionRadius * pickdir, Location, false);
				if ( (HitActor != None) && ((HitNormal Dot pickDir) < -0.6) )
					Destination = HitLocation - 2 * CollisionRadius * pickdir;
			}
		}

	}
}


state Hunting
{
ignores EnemyNotVisible;

	function PickDestination()
	{
	// copied all variables from ScriptedPawn.PickDestination(), because "Super(ScriptedPawn).PickDestination(bNoCharge)" does not compile
	local NavigationPoint path;
	local actor HitActor;
	local vector HitNormal, HitLocation, nextSpot, ViewSpot;
	local float posZ, elapsed;
	local bool bCanSeeLastSeen;

		if (QueenDestHave != QDH_No)
		{
			GotoState('Teleporting');
			Return;
		}
		// copied all remaining lines from ScriptedPawn.Hunting.PickDestination(), because "Super(ScriptedPawn).PickDestination(bNoCharge)" does not compile
		// If no enemy, or I should see him but don't, then give up
		if ( (Enemy == None) || (Enemy.Health <= 0) )
		{
			WhatToDoNext('','');
			return;
		}

		bAvoidLedges = false;
		elapsed = Level.TimeSeconds - HuntStartTime;
		if ( (elapsed > 30) && ((intelligence < BRAINS_Human) || (elapsed > 90)) )
		{
				WhatToDoNext('','');
				return;
		}

		if ( JumpZ > 0 )
			bCanJump = true;

		if ( ActorReachable(Enemy) )
		{
			if ( bIsBoss || (numHuntPaths < 8 + Skill) || (elapsed < 15)
				|| ((Normal(Enemy.Location - Location) Dot vector(Rotation)) > -0.5) )
			{
				Destination = Enemy.Location;
				MoveTarget = None;
				numHuntPaths++;
			}
			else
				WhatToDoNext('','');
			return;
		}
		numHuntPaths++;

		ViewSpot = Location + EyeHeight * vect(0,0,1);
		bCanSeeLastSeen = false;
		if ( intelligence > BRAINS_Reptile )
		{
			HitActor = Trace(HitLocation, HitNormal, LastSeenPos, ViewSpot, false);
			bCanSeeLastSeen = (HitActor == None);
			if ( bCanSeeLastSeen )
			{
				HitActor = Trace(HitLocation, HitNormal, LastSeenPos, Enemy.Location, false);
				bHunting = (HitActor != None);
			}
			else
				bHunting = true;
			if ( FindBestPathToward(Enemy) )
				return;
		}

		MoveTarget = None;
		if ( bFromWall )
		{
			bFromWall = false;
			if ( !PickWallAdjust() )
			{
				if ( CanStakeOut() )
					GotoState('StakeOut');
				else
					WhatToDoNext('', '');
			}
			return;
		}

		if ( !bIsBoss && (NumHuntPaths > 20) && ((Intelligence < BRAINS_Human) || (NumHuntPaths > 60)) )
		{
			WhatToDoNext('', '');
			return;
		}

		if ( LastSeeingPos != vect(1000000,0,0) )
		{
			Destination = LastSeeingPos;
			LastSeeingPos = vect(1000000,0,0);
			HitActor = Trace(HitLocation, HitNormal, Enemy.Location, ViewSpot, false);
			if ( HitActor == None )
			{
				If (VSize(Location - Destination) < 20)
				{
					HitActor = Trace(HitLocation, HitNormal, Enemy.Location, ViewSpot, false);
					if (HitActor == None)
					{
						SetEnemy(Enemy);
						return;
					}
				}
				return;
			}
		}

		bAvoidLedges = ( (CollisionRadius > 42) && (Intelligence < BRAINS_Human) );
		posZ = LastSeenPos.Z + CollisionHeight - Enemy.CollisionHeight;
		nextSpot = LastSeenPos - Normal(Enemy.Location - Enemy.OldLocation) * CollisionRadius;
		nextSpot.Z = posZ;
		HitActor = Trace(HitLocation, HitNormal, nextSpot , ViewSpot, false);
		if ( HitActor == None )
			Destination = nextSpot;
		else if ( bCanSeeLastSeen )
			Destination = LastSeenPos;
		else
		{
			Destination = LastSeenPos;
			HitActor = Trace(HitLocation, HitNormal, LastSeenPos , ViewSpot, false);
			if ( HitActor != None )
			{
				// check if could adjust and see it
				if ( PickWallAdjust() || FindViewSpot() )
					GotoState('Hunting', 'AdjustFromWall');
				else if ( bIsBoss || VSize(Enemy.Location - Location) < 1200 )
					GotoState('StakeOut');
				else
				{
					WhatToDoNext('Waiting', 'TurnFromWall');
					return;
				}
			}
		}
		LastSeenPos = Enemy.Location;
	}
}



State Teleporting
{
ignores TakeDamage, SeePlayer, EnemyNotVisible, HearNoise, KilledBy, Bump, HitWall, HeadZoneChange, FootZoneChange, ZoneChange, Falling, WarnTarget, Died;



	function ChooseDestination()
	{
	local NavigationPoint N;
	local vector ViewPoint, HitLocation, HitNormal, Best;
	local actor HitActor;
	local float rating, newrating, NeededRadius;

		Best = Location;
		if (QueenDestHave != QDH_No)
		{
			N = Level.NavigationPointList;
			rating = 0;
			NeededRadius = fMax(CollisionRadius, CollisionHeight) * 1.5; // 1.5 => keep some safaty distance
			QueenDestHave = QDH_No; // will be changed in loop, if a QueenDest is found
			while ( N != None )
			{
				if ( N.IsA('QueenDest'))
				{
					QueenDestHave = QDH_Yes;
					if ( ! RadiusActorHave(N, class'Pawn' , NeededRadius) ) // don't telefrag other Pawns
					{ // rate it
						newrating = 0;
						if ( Best == Location )
							Best = N.Location;
						ViewPoint = N.Location + EyeHeight * vect(0,0,1);
						HitActor = Trace(HitLocation, HitNormal, Enemy.Location, ViewPoint, false);
						if ( HitActor == None )
							newrating = 20000;

						newrating = newrating - VSize(N.Location - Enemy.Location) + 1000 * FRand() + 4 * VSize(N.Location - Location);
						if ( N.Location.Z > Enemy.Location.Z )
							newrating += 1000;

						if ( newrating > rating )
						{
							rating = newrating;
							Best = N.Location;
						}
					}
				}

				N = N.nextNavigationPoint;
			}
		}
		TelepDest = Best;
	}

}



defaultproperties
{
	MenuName="Queen"
	ProjectileSpeed=1200
	CollisionRadius=90
	CollisionHeight=107
}
Changes to UnrealI.Queen:
  • Queens spawned via factory do not telefrag other queens (based on function EncroachingOn())
  • Queens try to teleport only once if there is no QueenDest (based on variable QueenDestHave).
  • Queens do not telefrag other pawns on QueenDests.
  • ProjectileSpeed is used now.

Re: Avoid teleporting of Queens

Posted: Wed Jun 27, 2018 6:23 am
by sektor2111
Making things more complicated with writing patch modules - replacements, but is not the end of world here, all I have to say is Thanks so far. In other ground of deals, there is a server set by self person having fore-mentioned out-of mismatch stock queen reacting different located at unreal://64.94.238.23:7777. I could not convince them (services) to allow me to switch those files from System, so I have quit using System setting up a different configuration. By disabling XC Queen tweaking, I allow queens to run in "original". You can inspect maps with queens - including self explanatory MA-Queens and see if will ever break game as it was doing before... I'm not going to setup servers using default trash files ever.
To do: Inspecting that blob from UnrealShare, I see array error 5/5 in client so I think that is a nasty deal as long as it is... client code. Or I might try an XC_Actor there...
According to projectiles speed from me those are not going to be fixed, I have reasons for not unlocking these as configurable, some mappers likes to be retarded at random so I have no wish for doing damage with them unless you want to cap values at some normal limits for human beings living on Earth, leaving aliens to play in other location.

Re: Avoid teleporting of Queens

Posted: Tue Oct 02, 2018 4:24 am
by Barbie
Finally I did a mutator ("SBQueenSaver") that replaces the Queens of package UnrealI with an improved one. The improvements of the new Queen are:
  • No telefragging of others if spawned by a factory.
  • No telefragging of others if teleporting to a QueenDest.
  • Only one teleport attempt if there are no QueenDests.
  • The minimum time between two teleleports is adjustable.
  • The shield size is adjusted to the queen's size.
  • ProjectileSpeed is used now.
Download at usual place.

PS: Avoiding telefragging is important if an event is connected to the victim. The event will not be risen on telefragging.