Jump to content


Photo

Threat Calculation


10 replies to this topic

#1 WizWom

WizWom

    Wandering Kernel of Happiness

  • Members
  • 405 posts
  • Gender:Male
  • Location:Rosendale, MO

Posted 22 September 2006 - 08:35 PM

For My Tutu NPC, I've made a fairly sophisticated threat calculator, mainly for Mages.

generally, it decides how dangerous to th mage the nearest enemy closer than 8 (a distance which should take 2 seconds to cross) is and how dangerous the furthest spellcaster is (priority goes Mage, cleric, druid, bard, if I'm scripting right). It takes into account the mages resilience and the spellcaster's power. It then chooses between these two if both are present.

And since I keep the threat calculation, I can then have the script use different spells for differeing levels of danger - of course, I like putting out a magic missile or acid arrow to disrupt preferentially. Clerics, of course, should open with a disrupting insect swarm.

Anyway, it also can be extended to fighters, in that they can just choose to attack the target if they are ranging, or the nearest non-trivial if they are meleeing.

I'm basing it off the TAZQ series of scripts, but I'm ending up chopping stuff out because it will never be seen in tutu, and recoding almost all the tests :-)

#2 cirerrek

cirerrek

    Voiceless bilabial plosive

  • Gibberlings
  • 399 posts
  • Location:MO

Posted 23 September 2006 - 05:30 AM

WizWorm,

Threat assessment is pretty tricky, cool that you've worked something out that is effective.

Ideally you would be able to have a 'global' threat level = the amount of trouble the whole part is in e.g.,

Red = 1 Tarasque or 2 summoned demons + 2 mages + 2 Fighters + 2 Clerics
Yellow = 5 Fire Giants or 8 10th+ lvl creatures
Green = 10 Kobolds or 3 Carrion Crawlers

And then have an individual threat level based on who/what is currently attacking a particular party memember.

Then you would figure out some way to mesh the two systems to react appropriately e.g., the mage realizing that he is in serious trouble runs off towards your fighters to get some help with the Iron Golem that is trying to maul him/her.

Care to post some snippets with an explanation or is the code proprietary?

Does your threat assessment scale well? Tutu vs. BG2?

TAZQ series of scripts? ...Never heard of this system

Thanks,
Cirerrek

Be sure not to dive into the shallow end of your imagination - Grover

#3 WizWom

WizWom

    Wandering Kernel of Happiness

  • Members
  • 405 posts
  • Gender:Male
  • Location:Rosendale, MO

Posted 23 September 2006 - 07:42 AM

Well, the whole point was to make a scaling threat assessment, for Tutu. since what's really dangerous as 1st level isn't going to phase you when you've make 5th or 6th. So, you need to use your magic/items to battle a wolf at first level, but you probably won't break a sweat fighting a Dire wolf at 4th.

The scripts were an extension on someone's q-series scripts, off of sorcerer's place.
BG2 aiscripts by Tapio Kivikkola <zap@mad.scientist.com>
It included upgraded summons AI & somewhat better

Similiar to orginal Blucher's scripts, but usage of scrolls, some items and most of area spells are removed (in my game, however, Aerie still casts Fireball).
Also alchemy is removed.



#4 WizWom

WizWom

    Wandering Kernel of Happiness

  • Members
  • 405 posts
  • Gender:Male
  • Location:Rosendale, MO

Posted 23 September 2006 - 07:55 AM

As for the teamwork, have you looked at
http://www.citilink.com/~jch/bg/
He seems to have spent some time working on his scripts. I grabbed them, to see if he's got anything interesting in there.

#5 Gimble

Gimble
  • Members
  • 47 posts

Posted 26 September 2006 - 07:54 AM

Just to chime in, I'm now testing my own threat level system in IWD2. My brief experience seems to indicate that at least the following factors should be considered:
  • Number of non-disabled enemies
  • Number of nearby allies
  • Health (and status) of party
  • Presence of enemy spellcasters
  • Checks for (a few) particularly nasty enemy types
  • and, very importantly, Personal health
For my own system, I add or subtract from my threat levels based on the above, and then perform some sanity checks to ensure the threat level has not gotten too high or too low. After that, I translate the threat level value into a maximum spell level that I'm willing to use.

That made it much more trivial to think appropriately for spell and item usage: I'll gladly cast Mirror Image (spell level 2) or drink a Potion of Aid (spell level 2) if my MaxSpellLevel is 2 or higher.

An added bonus is that as I refine the list of threat contributors above, I merely have to adjust the maximum spell level appropriately as I find the threat system too lenient or too strict, and all the items/spells I have coded will "take care of themselves".

My testing so far has been pretty limited, but I've been happy with the system. I will admit that IWD2's scripting engine -- and allocation of enemies -- actually makes threat assessment a little easier than the BG2 engine IMO, but that's small consolation for the multitude of bugs that are in the engine overall. :)

As a secondary note, the inclusion of character-specific modifiers to threat level (most notably personal health) meant that a global threat level seemed less appropriate than a personal one. In addition, I found that global threat calculation had to be handled very carefully (to ensure that everyone isn't constantly trying to adjust it), so I've abandoned global threat level for now.

#6 WizWom

WizWom

    Wandering Kernel of Happiness

  • Members
  • 405 posts
  • Gender:Male
  • Location:Rosendale, MO

Posted 26 September 2006 - 11:04 AM

well, generally, my script starts with a "fix-up" section, which tests for low HP or poison and tries to remedy.

The, if I'm not in combat and see nothing threatening, I break.

Combat threat calculation is:
IF
	True()
THEN
	RESPONSE #100
		SetGlobal("WxNearDanger","LOCALS",0)
		SetGlobal("WxMageDanger","LOCALS",0)
		Continue()
END

IF
	Global("Debug","GLOBAL",1)
THEN
	RESPONSE #100
		PauseGame()
		Continue()
END

IF
	See(NearestEnemyOf(Myself))
	Range(LastSeenBy(Myself),8)
THEN
	RESPONSE #100
		SetGlobal("WxNearDanger","LOCALS",3)
		Continue()
END

IF
	HPLT(LastSeenBy(Myself),10)
	Range(LastSeenBy(Myself),8)
THEN
	RESPONSE #100
		IncrementGlobal("WxNearDanger","LOCALS",-1)
		Continue()
END

IF
	HPLT(LastSeenBy(Myself),5)
	Range(LastSeenBy(Myself),8)
THEN
	RESPONSE #100
		IncrementGlobal("WxNearDanger","LOCALS",-1)
		Continue()
END

IF
	HPGT(LastSeenBy(Myself),20)
	Range(LastSeenBy(Myself),8)
THEN
	RESPONSE #100
		IncrementGlobal("WxNearDanger","LOCALS",1)
		Continue()
END

IF
	HPGT(LastSeenBy(Myself),35)
	Range(LastSeenBy(Myself),8)
THEN
	RESPONSE #100
		IncrementGlobal("WxNearDanger","LOCALS",1)
		Continue()
END

IF
	HPGT(LastSeenBy(Myself),50)
THEN
	RESPONSE #100
		IncrementGlobal("WxNearDanger","LOCALS",1)
		Continue()
END

IF
	HPGT(LastSeenBy(Myself),65)
THEN
	RESPONSE #100
		IncrementGlobal("WxNearDanger","LOCALS",1)
		Continue()
END

IF
	HPGT(Myself,40)
	Range(LastSeenBy(Myself),8)
THEN
	RESPONSE #100
		IncrementGlobal("WxNearDanger","LOCALS",-1)
		Continue()
END

IF
	HPGT(Myself,30)
	Range(LastSeenBy(Myself),8)
THEN
	RESPONSE #100
		IncrementGlobal("WxNearDanger","LOCALS",-1)
		Continue()
END

IF
	HPGT(Myself,15)
	Range(LastSeenBy(Myself),8)
THEN
	RESPONSE #100
		IncrementGlobal("WxNearDanger","LOCALS",-1)
		Continue()
END

IF
	GlobalLT("WxNearDanger","LOCALS",0)
THEN
	RESPONSE #100
		SetGlobal("WxNearDanger","LOCALS",0)
		ChangeSpecifics(NearestEnemyOf(Myself),WWXJON_TRIVIAL)
		Continue()
END

IF
	GlobalGT("WxNearDanger","LOCALS",3)
THEN
	RESPONSE #100
		Shout(124)
		ChangeSpecifics(NearestEnemyOf(Myself),WXJON_TARGET)
		Continue()
END

IF
	OR(4)
		See([ENEMY.0.0.CLERIC_ALL])
		See([ENEMY.0.0.LONG_BOW])
		See([ENEMY.0.0.BARD_ALL])
		See([ENEMY.0.0.DRUID_ALL])
THEN
	RESPONSE #100
		SetGlobal("WxMageDanger","LOCALS",3)
		Continue()
END

IF
	GlobalGT("WxMagedanger","LOCALS",0)
	LevelLT(LastSeenBy(Myself),3)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",-1)
		Continue()
END

IF
	GlobalGT("WxMagedanger","LOCALS",0)
	LevelLT(LastSeenBy(Myself),5)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",-1)
		Continue()
END

IF
	GlobalGT("WxMagedanger","LOCALS",0)
	LevelGT(LastSeenBy(Myself),6)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",2)
		Continue()
END

IF
	GlobalGT("WxMagedanger","LOCALS",0)
	LevelGT(LastSeenBy(Myself),8)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",2)
		Continue()
END

IF
	GlobalGT("WxMagedanger","LOCALS",0)
	CheckStatGT(Myself,10,SAVEVSSPELL)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",1)
		Continue()
END

IF
	GlobalGT("WxMagedanger","LOCALS",0)
	CheckStatGT(Myself,13,SAVEVSSPELL)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",1)
		Continue()
END

IF
	GlobalGT("WxMagedanger","LOCALS",0)
	CheckStatGT(Myself,16,SAVEVSSPELL)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",1)
		Continue()
END

IF
	GlobalGT("WxMagedanger","LOCALS",0)
	CheckStatLT(Myself,6,SAVEVSSPELL)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",-1)
		Continue()
END

IF
	HPGT(Myself,40)
	GlobalGT("WxMagedanger","LOCALS",0)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",-1)
		Continue()
END

IF
	HPGT(Myself,30)
	GlobalGT("WxMagedanger","LOCALS",0)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",-1)
		Continue()
END

IF
	HPGT(Myself,15)
	GlobalGT("WxMagedanger","LOCALS",0)
THEN
	RESPONSE #100
		IncrementGlobal("WxMageDanger","LOCALS",-1)
		Continue()
END

IF
	GlobalLT("WxMagedanger","LOCALS",0)
THEN
	RESPONSE #100
		SetGlobal("WxMageDanger","LOCALS",0)
		ChangeSpecifics(LastSeenBy(Myself),WWXJON_TRIVIAL)
		Continue()
END

IF
	GlobalGT("WxMagedanger","LOCALS",0)
	!See([0.0.0.0.WXJON_TARGET])
THEN
	RESPONSE #100
		ChangeSpecifics(LastSeenBy(Myself),WXJON_TARGET)
		Continue()
END

IF
	GlobalGT("WxMageDanger","LOCALS",0)
	See([0.0.0.0.WXJON_TARGET])
	OR(4)
		See([ENEMY.0.0.CLERIC_ALL])
		See([ENEMY.0.0.LONG_BOW])
		See([ENEMY.0.0.BARD_ALL])
		See([ENEMY.0.0.DRUID_ALL])
	LocalsGT("WxMageDanger","WxNearDanger")
THEN
	RESPONSE #100
		ChangeSpecifics(LastSeenBy(Myself),WXJON_TARGET)
		ChangeSpecifics(NearestEnemyOf(Myself),0)
		Continue()
END

So, if I have no enemy with a WXJON_TARGET, then I know I am not threatened.
If I see an enemy with WXJON_TARGET, then I can decide whether it is a mage or a melee combatant, if it is a mage, I can use blocks like:

IF
	LocalsGT("WxMageDanger","WxNearDanger")
	See([0.0.0.0.WXJON_TARGET])
	CheckStatLT(Myself,35,SPELLFAILUREMAGE)
	CheckStatLT(LastSeenBy(Myself),50,RESISTMAGIC)
	!HasBounceEffects(LastSeenBy(Myself))
	!HasItemEquiped("mageamul",LastSeenBy(Myself)) // Necklace
	!StateCheck(LastSeenBy(Myself),STATE_INVISIBLE)
	!StateCheck(LastSeenBy(Myself),STATE_IMPROVEDINVISIBILITY)
	CheckStatLT(LastSeenBy(Myself),25,RESISTACID)
	HaveSpell(WIZARD_MELF_ACID_ARROW)
THEN
	RESPONSE #100
		SetInterrupt(FALSE)
		SetGlobalTimer("GBHalfAttack","LOCALS",ONE_ROUND)
		Spell(LastSeenBy(Myself),WIZARD_MELF_ACID_ARROW)
END

The "GBHalfAttack" bit is to let the next pass through the script use a ranged weapon, so I don't waste the rest of the round.

#7 cirerrek

cirerrek

    Voiceless bilabial plosive

  • Gibberlings
  • 399 posts
  • Location:MO

Posted 26 September 2006 - 06:53 PM

Wizworm,

Not sure about BG1, but it BG2, you can break the game by changing specifics of a character. That is why I dropped the ChangeSpecifics targeting from the eSeries and went to using Detectable Spells (not that it doesn't have its issues).
Cirerrek

Be sure not to dive into the shallow end of your imagination - Grover

#8 WizWom

WizWom

    Wandering Kernel of Happiness

  • Members
  • 405 posts
  • Gender:Male
  • Location:Rosendale, MO

Posted 26 September 2006 - 07:12 PM

As far as it goes, I change specifics of NPC, not characters...

I'm running this under tutu, so the engine is BG2. I saw the note about multiplayer using specific; I would expect they use it to tell who controlls what sprites.

It's a shame, because othewise I can't really make a turing machine, as I have no real way to store data. It's a bit of a hack, but it was seeming to work.

Edited by WizWom, 26 September 2006 - 07:15 PM.


#9 cirerrek

cirerrek

    Voiceless bilabial plosive

  • Gibberlings
  • 399 posts
  • Location:MO

Posted 26 September 2006 - 08:27 PM

As far as it goes, I change specifics of NPC, not characters...

I'm running this under tutu, so the engine is BG2. I saw the note about multiplayer using specific; I would expect they use it to tell who controlls what sprites.

It's a shame, because othewise I can't really make a turing machine, as I have no real way to store data. It's a bit of a hack, but it was seeming to work.


--ChangeSpecifics(NearestEnemyOf(Myself),WWXJON_TRIVIAL)

I meant NPCs, darn esoteric terminology...

Wizworm, ah, TuTu. Is there someway to search as see if any ingame scripts are checking for Specifics to move the plot along? If BG1 (albeit in the BG2 engine) isn't using Specifics to advance quests or the plot line along, then you would still be okay using it.

Seems like you are saying that multiplayer definitely does. In that case, it would probably be a bad idea to use the scripts for multiplayer games.
Cirerrek

Be sure not to dive into the shallow end of your imagination - Grover

#10 WizWom

WizWom

    Wandering Kernel of Happiness

  • Members
  • 405 posts
  • Gender:Male
  • Location:Rosendale, MO

Posted 26 September 2006 - 08:48 PM

Well, BG2 uses specifics for certain NPCs, from what i can see. So, I'm not sure it's wise to do this, anyway.

Since I know whether to target the NearestEnemy() or the LastSeen of a mage class, then I suppose I'll have to have the targeting in the blocks :-(

#11 Taza

Taza
  • Members
  • 6 posts
  • Location:Finland

Posted 04 August 2009 - 03:38 PM

This coming extremely late, but those scripts are mainly Blucher's scripts. I just adjusted them, mostly to avoid nuking neutrals.



Reply to this topic



  


0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users