Auto Combat AI on PC script help needed

@kevL_s

LOL!

OK, grabbing the can 'o worms opener … the bottom line is I would currently have to rely on a player using the right-click “attack target” option that allows the “GetPlayerCurrentTarget” to become the player’s “chosen” option to allow combat to occur.

Here is my function (part of a larger script) that cycles through the party for those PCs with a target and unlocks their non-attack stance … NB: This function fires for the HOST (or single leader player) only to prevent loop overload. This then loops through the party members and applies the same as your script when the controlled PC does not have a valid target (stops the retaliation). When the right-click attack is used by the player, the target becomes valid for them and allows them to attack as normal. In my code, I also reallocate the target in the DisplayTargets(oPC); function that comes after so that they only have to keep the target “targeted” for the first attack. Thereafter, they can “lose the target” by right-clicking anywhere on the screen and the target is NOT lost. To lose the target again, the player would click the attack icon in their PC queue (to remove it), which would end their attacks. I also added the same end if they moved, which this function handles. NB: At some point I may consider making a normal “left click” select the target (like a right-click), but that may not be possible as I have not looked too close at the xml callbacks required - so it may not be possible. (Although, a normal right-click attack for a possessed PC to get the action started for the player seemed reasonable to me anyway.)

Let me know if you want further clarification on what I do … :slight_smile:

void UpdateTargetGUI(object oPC);
void UpdateTargetGUI(object oPC)
{	    
	object oFM = GetFirstFactionMember(oPC, FALSE);
			
	while(oFM != OBJECT_INVALID)
	{	
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// KEEP A POSSESSED PC NO ACTION UNLESS A VALID TARGET GIVEN - THIS DOES WORK BUT ...
		// NEEDS SOME REPORT FEEDBACK TIDYING UP AND REQUIRES RIGHT CLICK TO INITIATE (AND MUST KEEP TARGET FOR 1 ROUND)
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		
		if(GetControlledCharacter(oFM) == oFM)
		{
			int iACTION = GetCurrentAction(oFM);
			//SendMessageToPC(oFM, " >>> " + IntToString(iACTION));
			
			//SendMessageToPC(GetFirstPC(), GetFirstName(oFM) + " CURRENT TARGET >>> " + GetName(GetLocalObject(oFM, "N2_PLAYER_QUEUED_TARGET")));	
			
			if(iACTION == ACTION_MOVETOPOINT)
			{
				DeleteLocalObject(oFM, "N2_PLAYER_QUEUED_TARGET");
			}
				
			object oTarget = GetPlayerCurrentTarget(oFM);
			
			if(oTarget == OBJECT_INVALID && GetLocalObject(oFM, "N2_PLAYER_QUEUED_TARGET") == OBJECT_INVALID)
			{
				if(iACTION == ACTION_ATTACKOBJECT || iACTION == ACTION_INVALID)
				{
					AssignCommand(oFM, ClearAllActions());
					DeleteLocalObject(oFM, "N2_PLAYER_QUEUED_TARGET");
				}
			}
			
			else
			{			
				SetLocalObject(oFM, "N2_PLAYER_QUEUED_TARGET", oTarget);
			}
		}
		
		else
		{
			AssignCommand(oFM, StorePlayerQueuedTarget());
		}
        
		oFM = GetNextFactionMember(oPC, FALSE);
    }
	
	//SendMessageToAllPCs("<<< UPDATING >>>");
	
	DisplayTargets(oPC);	
}

And here is a snippet from the DisplayTargets function that also stores the target … via another loop!

// VALID TARGET - RETRIEVE ANY POTENTIAL ATTACK TARGET OBJECT NAME (RISK)		
		object oEnemyTarget = GetLocalObject(oFM, "N2_PLAYER_QUEUED_TARGET");
		
		if(oEnemyTarget == OBJECT_INVALID){oEnemyTarget = GetAttackTarget(oFM);}		
		
		if(GetIsDead(oEnemyTarget)){oEnemyTarget = OBJECT_INVALID;}
						
		// STORE
		SetLocalObject(oFM, "N2_PLAYER_QUEUED_TARGET", oEnemyTarget);

CAVEAT: This assumes the OC combat system is still working along the lines mine does after all the alterations I have made … which I believe it should do at this point. i.e. This code would only be currently applied when using my TB mode in my own setup.

Retiring from main computer for the night now … :sleeping: … But will hang around for brief response if needed. If I miss any now, I’ll get back to you tomorrow. :+1:

np. Get a good sleep, all I need is ideas and your stuff gives me a few …

 
edit →

in ActionQueue.xml w/ scriptloadable=“true”

<UIButton name="kL_antiretaliation" x="5" y="9" width="15" height="15"
OnLeftClick='UIObject_MISC_ExecuteServerScript("gui_antiretaliation_toggle")'
OnUpdate='UIObject_MISC_ExecuteServerScript("gui_antiretaliation")' update="true" updaterate="0.1" />

(there’s a small circle in the upperleft corner of the action queue and this is an invisible button on it)

 

// 'gui_antiretaliation_toggle'
/*
	Gui script. Fires from ActionQueue button 'kL_antiretaliation'.

	Toggles the player's anti-retaliation state.
*/

const string AR = "antiret";

// OBJECT_SELF is the MainPC of the player whose gui this is fired by.
void main()
{
	object oPc  = OBJECT_SELF;
	object oPcc = GetControlledCharacter(oPc);

	if (!GetLocalInt(oPc, AR))
	{
		SetLocalInt(oPc, AR, TRUE);
		SendMessageToPC(oPcc, "<c=lightcoral>Anti-retaliation is ON</c>");
	}
	else
	{
		DeleteLocalInt(oPc, AR);
		SendMessageToPC(oPcc, "<c=mediumspringgreen>Anti-retaliation is OFF</c>");
	}
}

 

// 'gui_antiretaliation'
/*
	Gui script. Fires from ActionQueue button 'kL_antiretaliation' with an
	updaterate of 0.1 sec

	Stops player-controlled-characters from auto-retaliating when attacked.
*/

const string AR = "antiret";

// OBJECT_SELF is the MainPC of the player whose gui this is fired by.
void main()
{
	if (!GetPause())
	{
		object oPc = OBJECT_SELF;
		if (GetLocalInt(oPc, AR))
		{
			oPc = GetControlledCharacter(oPc);
			if (GetCurrentAction(oPc) == ACTION_ATTACKOBJECT)
			{
				AssignCommand(oPc, ClearAllActions(TRUE));
			}
		}
	}
}

Works great. Thanks Lance/demoix,

uh … what I want this for ? Testing combat stuff on monsters without clubbing them into the ground … eg.

1 Like

@kevL_s

Good to hear you have it working! :grinning:

I think using a basic toggle switch is the cleanest way to go. I was trying to incorporate it alongside the other systems I have in place, but the option to retaliate or not is something too situational to adopt to either one mode of combat or another.

I’ll have a think where to put it, but I do like the idea of using that little circle (with the sword) in the action queue like you have. It may not be obvious enough though … But maybe with a tooltip when hovered? :thinking: Or in my main menu?

I’ll have a think, but I hope to have it in the next release so the player has the option.

Another gameplay issue solved. :+1:

EDIT: You know, sometimes I am tempted more and more to implement a full blown TB system when I mess with this kind of thing. Maybe when I have completed the campaign that will be my next project. :slight_smile:

@demoix

This same principle may possibly be used to make your possessed PC use AI. Not tested.

I may play around with this later and may end up with a three way toggle switch. Although, actually just toggle this option and allow the AI toggle to determine if AI used. I’ll have a think about the best combination.

1 Like

making it dependent on having a current target should, i think, be okay for general usage …

don’t forget that it’s possible to hook up an ExecuteServerScript call from the RMB menu-button (i think). I thought about using that to turn “retaliation” back on again … but i wouldn’t like to have to initiate attacks w/ the RMB-menu and not simply Lclick

i haven’t checked but, I think the stock auto-retaliate will force the opponent to become the player’s current target … something to be wary of …

 

well, since my implementation is just for me I know it’s there. But what I first thought of doing was enlarging the ActionQueue horizontally and inserting a visible button about 25px square w/ images that indicate on or off state, snugged in just beneath the circle and sword …

it just makes sense to have it on the ActionQueue gui,

@kevL_s

Yes, I agree. I have updated the switch to the same location now as you (action queue tiny sword) and (in case players want it), I added a tooltip to remind them it’s there. However, as there is no permanent visual indication of which state it is in, then having a larger noticeable button would probably be more practical as you say.

Ideally, being able to tie in a callback on a left click to re-enable combat would probably be neat, but then again, as it only affects the PC currently possessed, the one time right-click attack may still be a viable option for the few times it may serve a use (as it currently stands). Of course, it has the potential to be something more useful (perhaps), especially if considering some sort of TB system where we NEED to force non-retaliation.

1 Like

here’s an idea. Could you make a copy of the ActionQueue background graphic and swap the two back and forth? give the circle/sword a red background when retaliation is off …

( am gonna try that, so i can see at a glance what state currently is )

unfortunately my artistic abilities are basically nill so I’ll just plop down a bunch of red pixels …

 
actionqueue_antiretaliation_on
told ya … someone take gimp away from me pls.

1 Like

@kevL_s

Yes, this is possible, as I already do this for one of my own GUI buttons.

I believe I used existing colour overlays available in the data files.

Not at main computer at the moment, but employing a colour overlay should definitely be doable. If you get the XML code done before me (:zzz: for me now), do let me know if you can share. Otherwise, I’ll take a look tomorrow and let you know. :+1:

Edit: Cool! If you good to share, I’d use it!

ActionQueue.xml

	<UIIcon name="AQ_BG" x="0" y="0" width="PARENT_WIDTH" height="PARENT_HEIGHT"
	img="action_queue_md.tga" />

	<UIIcon name="AQ_BG_RETALIATE" x="0" y="0" width="PARENT_WIDTH" height="PARENT_HEIGHT"
	img="action_queue_md_retal.tga" hidden="true" />

 

// 'gui_antiretaliation_toggle'
/*
	Gui script. Fires from ActionQueue button 'kL_antiretaliation'.

	Toggles the player's anti-retaliation state.
*/

const string AR = "antiret";

// OBJECT_SELF is the MainPC of the player whose gui this is fired by.
void main()
{
	object oPc  = OBJECT_SELF;
	object oPcc = GetControlledCharacter(oPc);

	int bAr = FALSE;

	if (!GetLocalInt(oPc, AR))
	{
		SetLocalInt(oPc, AR, TRUE);
		SendMessageToPC(oPcc, "<c=lightcoral>Anti-retaliation is ON</c>");

		bAr = TRUE;
	}
	else
	{
		DeleteLocalInt(oPc, AR);
		SendMessageToPC(oPcc, "<c=mediumspringgreen>Anti-retaliation is OFF</c>");
	}

	SetGUIObjectHidden(oPc, "SCREEN_ACTIONQUEUE", "AQ_BG",            bAr);
	SetGUIObjectHidden(oPc, "SCREEN_ACTIONQUEUE", "AQ_BG_RETALIATE", !bAr);
}
1 Like

@kevL_s

Great!

I’ll grab that tomorrow! :+1:

Until then … Goodnight! :grinning::zzz:

1 Like

but your ActionQueue is probably using a different background graphic … mine is based on Charlie’s UI i believe.

ps. lesson learned: keep the red subtle

1 Like

@kevL_s

Just caught me … I can probably adapt it ok. Worse case, I’ll take a look for the UI on the vault and work from there.

:+1:

1 Like

@Lance_Botelle if you have gimp (and everyone should…) make a copy of your actionqueue background, open it in Gimp, just plop down a bit of (subtle) red around the sword and Export … as TGA … gimp’s default tga settings work here

 
even better, don’t bother with UIIcon name="AQ_BG_RETALIATE" and SetGUIObjectHidden()

just use

	string sTexture;

	if (!GetLocalInt(oPc, AR))
	{
		SetLocalInt(oPc, AR, TRUE);
		SendMessageToPC(oPcc, "<c=lightcoral>Anti-retaliation is ON</c>");

		sTexture = "action_queue_md_retal.tga";
	}
	else
	{
		DeleteLocalInt(oPc, AR);
		SendMessageToPC(oPcc, "<c=mediumspringgreen>Anti-retaliation is OFF</c>");

		sTexture = "action_queue_md.tga";
	}

	SetGUITexture(oPc, "SCREEN_ACTIONQUEUE", "AQ_BG", sTexture);
1 Like

@kevL_s

Definitely. :+1:

I have the free Paint prog that I use now and then. Is this similar to Gimp?

And got this result … I made it slightly brighter because I am colour blind and sometimes need more vibrant colours to notice them.

image

We are the artist masters! :wink:

By the way, I already had Charlie UI images in a folder, so it was fairly straightforward to change … and I went for the slightly larger (6 queue window) as well.

1 Like

I hear only good things about Paint .net … gimp has so many things it makes ya go crosseyed … so I use gimp :|

i burned and dodged and paintbrushed and penciled [and smudged] and after many reloads →

actionqueue_retaliate_on

deviantart look out :\

ah neat ! Charlie did some great stuff for nwn2 …

1 Like