ScriptedActions in UT99

Discussions about Coding and Scripting
Post Reply
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

ScriptedActions in UT99

Post by Gustavo6046 »

I was angry at how Bot would be dumb at most matches with actual players even at high skill levelz.

So I decided to code this 'little bonus':

Code: Select all

//=============================================================================
// ScriptedActions.
//=============================================================================
class ScriptedActions expands NavigationPoint;

struct ScriptArgument
{
	var name TagArguments[2];
	var int NumberArgument;
};

var(Scripting) ScriptArgument ScriptingArguments[32];
var Pawn PawnsActing[64];
var int PawnActionIndexes[64];
var int NumActions;

var(Scripting) enum EScriptingAction
{
	SA_None,
	SA_TriggerActor,
	SA_TriggerEvent,
	SA_EndActions,
	SA_TranslocateTo,
	SA_TargetPawn,
	SA_CauseEvent,
	SA_TransferTo,
	SA_TransferIfHealthy,
	SA_TransferIfInState,
} Actions[32];

function EndActions(Pawn Other, int Index)
{
	local int i;

	for ( i = Index; i < 63; i++ )
	{
		if ( PawnsActing[i + 1] == None )
			break;

		PawnsActing[i] = PawnsActing[i + 1];
		PawnActionIndexes[i] = PawnActionIndexes[i + 1];
	}
}

function Actor DoAction(EScriptingAction Action, ScriptArgument Argument, Pawn Other, int ActionIndex)
{
	local NavigationPoint NP;
	local Trigger T;
	local Actor A;
	local Pawn P;

	if ( Action == SA_TransferTo && Other.IsInState(Argument.TagArguments[0]) )
	{
		foreach AllActors(class'NavigationPoint', NP)
			if ( NP.Name == Argument.TagArguments[0] )
				return NP;

		return None;
	}


	if ( Action == SA_TransferIfInState && Other.IsInState(Argument.TagArguments[0]) )
	{
		foreach AllActors(class'NavigationPoint', NP)
			if ( NP.Name == Argument.TagArguments[1] )
				return NP;

		return None;
	}

	else if ( Action == SA_TransferIfHealthy && Other.Health > Argument.NumberArgument )
	{
		foreach AllActors(class'NavigationPoint', NP)
			if ( NP.Name == Argument.TagArguments[0] )
				return NP;

		return None;
	}

	else if ( Action == SA_TriggerActor )
	{
		foreach AllActors(class'Actor', A)
			if ( A.Name == Argument.TagArguments[0] )
				break;

		foreach AllActors(class'Trigger', T)
		{
			if ( A == None )
				return None;

			if ( T.Event == A.Tag )
				return T;
		}
	}

	else if ( Action == SA_TriggerEvent )
	{
		foreach AllActors(class'Trigger', T)
			if ( T.Event == Argument.TagArguments[0] )
				return T;
		
		return None;
	}

	else if ( Action == SA_EndActions )
	{
		EndActions(Other, ActionIndex);

		return None;
	}

	else if ( Action == SA_TargetPawn )
	{
		foreach AllActors(class'Pawn', P)
			if ( P.Name == Argument.TagArguments[0] )
				break;

		return P;
	}

	else if ( Action == SA_CauseEvent )
	{
		foreach AllActors(class'Actor', A, Argument.TagArguments[0])
			A.Trigger(self, Other);

		return None;
	}

	warn(self$"'s action "$Action$"did not match any in EScriptingAction enum!");
	return None;
}

function Actor ParseAction(int actionIndex, Pawn Other)
{
	if ( actionIndex > 31 )
		return None;

	return DoAction(Actions[actionIndex], ScriptingArguments[actionIndex], Other, actionIndex);
}

function Actor SpecialHandling(Pawn Other)
{
	local int i;
	local Pawn P;
	local Actor A;

	for ( i = 0; i < 64; i++ )
		if ( PawnsActing[i] == Other || PawnsActing[i] == None )
			break;

	if ( PawnsActing[i] == None )
	{
		PawnsActing[i] = Other;
		PawnActionIndexes[i] = 0; 
	}

	A = ParseAction(PawnActionIndexes[i], Other);

	if ( PawnActionIndexes[i] < 31 )
		PawnActionIndexes[i] += 1;
	
	else
		EndActions(Other, i);

	return A;
}
I am only keeping this and Caio Engine projects (2) so I did really reduce on total work per day :D
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

Re: ScriptedActions in UT99

Post by Gustavo6046 »

Sorry for the bump, but at least this isn't a double post :P

Doom community was being a freak considering my projects, so I'm back for good now. What did you think of Scr-- oh snap, I forgot to test it! Just a second.
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
User avatar
Dr.Flay
Godlike
Posts: 3347
Joined: Thu Aug 04, 2011 9:26 pm
Personal rank: Chaos Evangelist
Location: Kernow, UK
Contact:

Re: ScriptedActions in UT99

Post by Dr.Flay »

If you are serious about this script you would be using it all the time, so not need to go and test.

There are mods such as XBots/Adjustobots that let you change the minimum and maximum skills, and the speed at which they change.
http://www.ecoop.tk/load/loathsomesbotp ... s/1-1-0-13
Then there is the ultimate Bot AI mod by Higor "Ferbotz"
https://www.ut99.org/viewtopic.php?f=7&t=3805

Can you explain what your script is for, and why it is different to the 2 mentioned above ?
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

Re: ScriptedActions in UT99

Post by Gustavo6046 »

Dr.Flay wrote:Can you explain what your script is for, and why it is different to the 2 mentioned above ?
It is basically a NavigationPoint with an array of actions and their arguments. The bots try to execute the actions and their arguments in a order, each action executed once as the bot reaches the NavigationPoint, and everytime the bot reaches the ScriptedActions actor, the next action is played.

Quite a bit similiar to a UT200x actor which name I'm yet to lookup.
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
User avatar
Dr.Flay
Godlike
Posts: 3347
Joined: Thu Aug 04, 2011 9:26 pm
Personal rank: Chaos Evangelist
Location: Kernow, UK
Contact:

Re: ScriptedActions in UT99

Post by Dr.Flay »

thankyou, that should make it easier for people to decide if they want to look at or try your script :tu:
User avatar
Hellkeeper
Inhuman
Posts: 903
Joined: Tue Feb 25, 2014 12:32 pm
Personal rank: Soulless Automaton
Location: France
Contact:

Re: ScriptedActions in UT99

Post by Hellkeeper »

I guess this is inspired by the ScriptedSequence actor from UT2003?
You must construct additional pylons.
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

Re: ScriptedActions in UT99

Post by Gustavo6046 »

Hellkeeper wrote:I guess this is inspired by the ScriptedSequence actor from UT2003?
Yes, you got it!

By the way, how do I make a forced path between the actor and any Translocation Targets?
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
User avatar
Hellkeeper
Inhuman
Posts: 903
Joined: Tue Feb 25, 2014 12:32 pm
Personal rank: Soulless Automaton
Location: France
Contact:

Re: ScriptedActions in UT99

Post by Hellkeeper »

Do you mean how to make a bot teleport?
You put a LiftExit where the bot will "land", you put a TranslocDest above it and then you put the same thing in the LiftExits' and TranslocDest's s LiftTag.
You must construct additional pylons.
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

Re: ScriptedActions in UT99

Post by Gustavo6046 »

Hellkeeper wrote:Do you mean how to make a bot teleport?
You put a LiftExit where the bot will "land", you put a TranslocDest above it and then you put the same thing in the LiftExits' and TranslocDest's s LiftTag.
I meant I wanted a path between the ScriptedActions actor and the NavigationPoint it set it's translocation target to.

Idea! What if I make the ScriptedActions class a LiftExit subclass?
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
User avatar
PrinceOfFunky
Godlike
Posts: 1200
Joined: Mon Aug 31, 2015 10:31 pm

Re: ScriptedActions in UT99

Post by PrinceOfFunky »

Gustavo6046 wrote:
Hellkeeper wrote:Do you mean how to make a bot teleport?
You put a LiftExit where the bot will "land", you put a TranslocDest above it and then you put the same thing in the LiftExits' and TranslocDest's s LiftTag.
I meant I wanted a path between the ScriptedActions actor and the NavigationPoint it set it's translocation target to.

Idea! What if I make the ScriptedActions class a LiftExit subclass?
You can use InterpolationPoints, you can spawn them and set thir values dynamically, they can work as more detailed teleports.
I use them for the "ghost" player in the UnrealRace project.
"Your stuff is known to be buggy and unfinished/not properly tested"
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

Re: ScriptedActions in UT99

Post by Gustavo6046 »

PrinceOfFunky wrote:
Gustavo6046 wrote:
Hellkeeper wrote:Do you mean how to make a bot teleport?
You put a LiftExit where the bot will "land", you put a TranslocDest above it and then you put the same thing in the LiftExits' and TranslocDest's s LiftTag.
I meant I wanted a path between the ScriptedActions actor and the NavigationPoint it set it's translocation target to.

Idea! What if I make the ScriptedActions class a LiftExit subclass?
You can use InterpolationPoints, you can spawn them and set thir values dynamically, they can work as more detailed teleports.
I use them for the "ghost" player in the UnrealRace project.
No! I want an AI path between the ScriptedActions actor and the NavigationPoint it targets! ;_;

EDIT: After some few edits, but it seems the bots don't want to translocate to the target LiftExit...
Code:

Code: Select all

//=============================================================================
// ScriptedActions.
//=============================================================================
class ScriptedActions expands LiftExit;

struct ScriptArgument
{
	var() string StringArguments[2];
	var() name TagArguments[2];
	var() int NumberArguments[2];
	var() class ClassArgument;
};

var(Scripting) ScriptArgument ScriptingArguments[32];
var Pawn PawnsActing[64];
var int PawnActionIndexes[64];

var(Scripting) enum EScriptingAction
{
	SA_None,
	SA_TriggerActor,
	SA_TriggerEvent,
	SA_EndActions,
	SA_TranslocateTo,
	SA_TargetPawn,
	SA_CauseEvent,
	SA_TransferTo,
	SA_TransferIfHealthy,
	SA_TransferIfInState,
	SA_ShootAtAndGoTo,
	SA_SpawnObjectAndGoTo,
} Actions[32];

function EndActions(Pawn Other, int Index)
{
	local int i;

	for ( i = Index; i < 63; i++ )
	{
		if ( PawnsActing[i + 1] == None )
			break;

		PawnsActing[i] = PawnsActing[i + 1];
		PawnActionIndexes[i] = PawnActionIndexes[i + 1];
	}
}

function Actor DoAction(EScriptingAction Action, ScriptArgument Argument, Pawn Other, int ActionIndex)
{
	local NavigationPoint NP;
	local Trigger T;
	local Actor A;
	local Pawn P;
	local Bot B;
	local Inventory In;

	if ( Action == SA_TransferTo && Other.IsInState(Argument.TagArguments[0]) )
	{
		foreach AllActors(class'NavigationPoint', NP)
			if ( NP.Name == Argument.TagArguments[0] )
				return NP;

		return None;
	}

	if ( Action == SA_TranslocateTo )
	{
		foreach AllActors(class'Actor', A)
			if ( A.name == Argument.TagArguments[0] )
			{
				B = Bot(Other);

				if ( B == None )
					return None;

				if ( (B.MyTranslocator == None) || (B.MyTranslocator.TTarget != None) )
					return None;

				if ( !B.bCanTranslocate )
					return None;

				B.TranslocateToTarget(A);
				return A;
			}
	}

	if ( Action == SA_TransferIfInState && Other.IsInState(Argument.TagArguments[0]) )
	{
		if ( Other.IsInState(Argument.TagArguments[0]) )
			foreach AllActors(class'NavigationPoint', NP)
				if ( NP.Name == Argument.TagArguments[1] )
					return NP;

		return None;
	}

	else if ( Action == SA_ShootAtAndGoTo )
	{
		foreach AllActors(class'Actor', A)
			if ( A.Name == Argument.TagArguments[0] )
				break;

		if ( A == None )
			return None;

		In = Other.FindInventoryType(Argument.ClassArgument);

		if ( In == None )
			return None;

		Other.Weapon = Weapon(In);
		Other.SetRotation(Rotator(A.Location - Other.Location));
		Other.FireWeapon();

		foreach AllActors(class'NavigationPoint', NP)
			if ( NP.Name == Argument.TagArguments[1] )
				return NP;
	}

	else if ( Action == SA_TransferIfHealthy && Other.Health > Argument.NumberArguments[0] )
	{
		if ( Other.Health > Argument.NumberArguments[0] )
			foreach AllActors(class'NavigationPoint', NP)
				if ( NP.Name == Argument.TagArguments[0] )
					return NP;

		return None;
	}

	else if ( Action == SA_TriggerActor )
	{
		foreach AllActors(class'Actor', A)
			if ( A.Name == Argument.TagArguments[0] )
				break;

		foreach AllActors(class'Trigger', T)
		{
			if ( A == None )
				return None;

			if ( T.Event == A.Tag )
				return T;
		}
	}

	else if ( Action == SA_TriggerEvent )
	{
		foreach AllActors(class'Trigger', T)
			if ( T.Event == Argument.TagArguments[0] )
				return T;
		
		return None;
	}

	else if ( Action == SA_EndActions )
	{
		EndActions(Other, ActionIndex);

		return None;
	}

	else if ( Action == SA_TargetPawn )
	{
		foreach AllActors(class'Pawn', P)
			if ( P.Name == Argument.TagArguments[0] )
				break;

		return P;
	}

	else if ( Action == SA_CauseEvent )
	{
		foreach AllActors(class'Actor', A, Tag)
			A.Trigger(self, Other);

		return None;
	}

	else if ( Action == SA_None )
	{
		return None;
	}

	warn(self$"'s action "$Action$" did not match any in EScriptingAction enum!");
	return None;
}

function Actor ParseAction(int actionIndex, Pawn Other)
{
	if ( actionIndex > 31 )
		return None;

	return DoAction(Actions[actionIndex], ScriptingArguments[actionIndex], Other, actionIndex);
}

function Actor SpecialHandling(Pawn Other)
{
	local int i;
	local Pawn P;
	local Actor A;
	local NavigationPoint NP;
	local NavigationPoint CNP;

	for ( i = 0; i < 64; i++ )
		if ( PawnsActing[i] == Other || PawnsActing[i] == None )
			break;

	if ( PawnsActing[i] == None )
	{
		PawnsActing[i] = Other;
		PawnActionIndexes[i] = 0; 
	}

	A = ParseAction(PawnActionIndexes[i], Other);

	PawnActionIndexes[i] += 1;	

	if ( A == None )
	{
		foreach AllActors(class'NavigationPoint', NP)
			if ( CNP == None || VSize(NP.Location - self.Location) < VSize(CNP.Location - self.Location) )
				CNP = NP;

		return CNP;
	}

	return A;
}
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
Post Reply