Advertisement
Guest User

Monster AI

a guest
Jan 20th, 2015
456
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 63.46 KB | None | 0 0
  1. Monster AI:
  2. So anyway, I've been coding on Incursion, trying to get it back to the spot where it produces a working executable (albeit with a bunch of stuff disabled), and it's going very slowly. I'm really realizing the enormity of the task I set out on here when I decided to refactor everything at once. On the good side, I'm very close (to an executable, not anything playable) at this point, and when the refactoring is truly all finished this will basically be the engine I plan to use for Return of the Forsaken.
  3. Anyway, as a preview and to elicit feedback, I figured I would post some of the new Behavior resources for the fully customizable resource-driven monster AI. This file doesn't compile at all yet -- I need to make improvements to the script compiler before it will take it -- so it's become kind of a sketchpad for theoretical ideas on monster tactics in Incursion. All the resources listed here that don't have code are just ideas so far -- definitely everything here won't be in the next release!
  4. Note that you just have to set a flag on any of these to make them player-accessible; they a player will be able to customize whether a follower is subject to a given Behavior or not by giving orders. I'll use a list like the 'pick up multiple objects' list on AutoLoot to let players turn lots of behaviors on an off for their companions at once.
  5. I don't expect people to really understand my code, and a lot of it is between revisions right now. I'm just posting it for interest's sake, if it amuses anybody. :)
  6.  
  7. -------------
  8.  
  9. Behaviour "Ooze Eats Metal Items" : BV_GENERIC
  10. {
  11. On Event EV_ISTARGET {
  12. return EActor->HasMFlag(M_METALIVORE) ?
  13. SHOULD_CAST_IT : CANNOT_CAST_IT;
  14. },
  15. EV_RATEITEM {
  16. if (EItem->isMetallic() &&
  17. EItem->Material() != MAT_ADAMANT)
  18. {
  19. e.targPri = 10 + EItem->Weight(false);
  20. e.targType = TT_ITEM;
  21. e.targWhy = TY_FOOD;
  22. e.targObj = EItem;
  23. return DONE;
  24. }
  25. return NOTHING;
  26. },
  27. EV_THINK {
  28. hObj hi;
  29. for (hi=EMap->FItemAt(EActor->x,EActor->y);hi;
  30. hi=EMap->NItemAt(EActor->x,EActor->y))
  31. if (EItem->isMetallic() &&
  32. EItem->Material() != MAT_ADAMANT)
  33. AddAct(ACT_CUSTOM,P_HIGH,hi,0);
  34. return NOTHING;
  35. },
  36. EV_CUSTOM {
  37. e.chResult = Throw(EV_EAT,EActor,ETarget);
  38. return DONE;
  39. };
  40. }
  41.  
  42.  
  43.  
  44. Behavior "Attack Mount in Melee" : BF_UNIVERSAL|BF_SETUP
  45. {
  46. Requires: BV_HAS_MTARG;
  47. On Event EV_THINK {
  48. if (!random(3))
  49. if (e.mtarg->hasStati(MOUNTED))
  50. e.mtarg = e.mtarg->getStatiObj(MOUNTED);
  51. };
  52. }
  53.  
  54.  
  55. Behavior "Attack Mount at Range" : BF_UNIVERSAL|BF_SETUP
  56. {
  57. Requires: BV_HAS_RTARG;
  58. On Event EV_THINK {
  59. if (!random(3))
  60. if (rtarg->hasStati(MOUNTED))
  61. rtarg = rtarg->getStatiObj(MOUNTED);
  62. return NOTHING;
  63. };
  64. }
  65.  
  66. Behavior "Fear From Injuries" : BF_UNIVERSAL|BF_EARLY
  67. {
  68. Cancels: BV_ENRAGED | BV_AFRAID;
  69. On Event EV_THINK {
  70. if (EActor->cHP*3 < (EActor->mHP+EActor->getAttr(A_THP)) {
  71. EActor->IDPrint(NULL,"The <hObj> turns to flee!", EActor);
  72. EActor->GainTempStati(AFRAID, NULL, -2, SS_MONI, FEAR_HP ,0,
  73. $"Fear From Injuries");
  74. EActorMB->AIFlags |= BV_AFRAID;
  75. }
  76. return NOTHING;
  77. },
  78. EV_ISTARGET {
  79. if (getAttr(A_MOV) == -20)
  80. return CANNOT_CAST_IT;
  81. return (hasMFlag(M_PSYCHO) || hasMFlag(M_MINDLESS) || isIllusion
  82. ()) ?
  83. CANNOT_CAST_IT : SHOULD_CAST_IT;
  84. };
  85. }
  86.  
  87. Behavior "Fear From Low Mana" : BF_UNIVERSAL|BF_EARLY
  88. {
  89. Cancels: BV_ENRAGED | BV_SESSILE | BV_AFRAID;
  90. On Event EV_THINK {
  91. if (EActor->cMana()*2 < EActor->tMana()) {
  92. EActor->IDPrint(NULL,"The <hObj> turns to flee!", EActor);
  93. EActor->GainTempStati(AFRAID, NULL, -2, SS_MONI, FEAR_MANA,0,
  94. $"Fear From Low Mana");
  95. EActorMB->AIFlags |= BV_AFRAID;
  96. }
  97. return NOTHING;
  98. },
  99. EV_ISTARGET {
  100. return (hasMFlag(M_PSYCHO) || hasMFlag(M_MINDLESS) || isIllusion
  101. ()) ?
  102. CANNOT_CAST_IT : SHOULD_CAST_IT;
  103. };
  104. }
  105.  
  106. Behavior "Recover From Fear" : BF_UNIVERSAL|BF_EARLY
  107. {
  108. Requires: BV_AFRAID;
  109. On Event EV_THINK {
  110. bool b;
  111. for (b=EActor->FirstStati(e,AFRAID,-1,SS_MONI);b;
  112. b=EActor->NextStati(e,AFRAID,-1,SS_MONI)) {
  113. if (e.vVal == FEAR_HP && EActor->cHP*3 > (EActor->mHP+EActor-
  114. >getAttr(A_THP))*2)
  115. EActor->RemoveThisStati();
  116. if (e.vVal == FEAR_MANA && EActor->cMana()*5 > EActor->tMana()
  117. *4)
  118. EActor->RemoveThisStati();
  119. }
  120. return NOTHING;
  121. };
  122. }
  123.  
  124. Behavior "Fix Trouble With Effect" : BF_UNIVERSAL
  125. {
  126. Requires: BV_HAS_EFFS;
  127. On Event EV_THINK {
  128. int16 tr, pri;
  129. if (EActor->hasEffToFix & EActor->Troubles) {
  130. for (tr=EActor->FirstTrouble();tr;tr=EActor->NextTrouble())
  131. EActor->AddAct(ACT_CAST,(tr/256) + ((e.bvFlags &
  132. BV_AFRAID) ? +1 : -1),
  133. EP_FIX_TROUBLE + ((tr & 0xFF)<<16));
  134. }
  135. return NOTHING;
  136. };
  137. }
  138.  
  139.  
  140. /* To support this, we should add back the OBJECTIVE stati
  141. specifically
  142. as a "location or creature to move toward" data structure, and give
  143. it a Val (Priority), Dur (abort if not reached after X turns), eID
  144. (causing Behavior), hObj (object to move towards) or Mag (x+y*256).
  145.  
  146. EActor->addMovementObjective(Target,PRI_HIGH,Dur,eID);
  147. EActor->addMovementObjective(x,y,PRI_NORMAL,Dur,eID);
  148.  
  149. We could do this with a Target instead of a Stati if we desired. We
  150. also need to add code for processing ACT_CAST to move toward the
  151. target of a touch spell if necessary, both for healing allies and
  152. for using hostile touch spells.
  153.  
  154. Since we're starting to look at spells as long-term objectives
  155. here,
  156. we also need to add a new function, calcCastingDiff(), for a given
  157. effect that returns a priority value based on how difficult it
  158. would
  159. be to cast the spell, taking into account mana, fatigue, risk, etc.
  160. We don't set movement objectives, and we abort the actual casting,
  161. if
  162. the priority returned by this function is higher than the priority
  163. of
  164. the ACT_CAST.
  165.  
  166. Use EventInfo as place to store disambiguators and such for
  167. iterators,
  168. to prevent recursive iteration, letting us do, frex, FirstStati.
  169.  
  170. BV_PALLY -- is an ally of the player
  171. BV_GOOD -- good alignment behavior
  172. BV_LAWFUL -- lawful alignment behavior
  173.  
  174. TO_MOVE_OBJ -- Movement Objective Target
  175. TO_KEEP_DIST -- Stay at least N squares away
  176.  
  177. Movement Rules:
  178. -- if highest priority movement objective is out of LOS,
  179. determine movement by pathfinding to that obj alone.
  180. -- if highest pri MO is pri >= PRI_EXTREME, travel only
  181. considering that objective
  182. -- otherwise, use gravity system
  183.  
  184. Dependencies Differ for Behaviors:
  185. BV_SHAPE (recalculate these on shapeshift)
  186. BV_ABILITY (recalc on levelup)
  187. BV_EFFECT (recalc with effectlist)
  188. BV_INVEN (recalc with inventory)
  189. BV_GROUP (recalc when party changes)
  190.  
  191.  
  192. --
  193. BV_LEADER
  194. BV_UNLED (leader or solo)
  195. BV_FOLLOWER
  196. --
  197.  
  198. When a Behavior returns CAN_CAST_IT, it's not automatic but can be
  199. issued as an order. This might depend on social stats -- a mage
  200. will be reluctant to "Take Point" unless the leader's really
  201. persuasive.
  202.  
  203. Allocate an int8* array of hasBehavior flags for each MonsterBrain
  204. on creation based on calling theGame->TotalBehaviors().
  205.  
  206. Favor (Neutrals) / Loyalty (Allies):
  207. -- gaining XP grants favor points
  208. -- fixing troubles grants favor points
  209. -- giving items that get equipped grants favor
  210. -- taking away items reduces loyalty
  211.  
  212. Strain
  213. -- RHostility sets base strain
  214. -- Getting critically wounded increases strain
  215.  
  216. Animal Emp should use the social framework for recruiting animals,
  217. ditto species affinity; work out how they stack (full AE ranks
  218. or
  219. +1/4 level bonus, whichever is better)
  220.  
  221.  
  222. scanNearbyArea()
  223. -- support function for monster navigation, when setting movement
  224. objectives you scan nearby squares until you find the closest
  225. one which matches some criteria. Used for:
  226. -- find lower-ceiling area when being shot by unreachable flyer
  227. -- find nearest route out of bad fields that are hurting you,
  228. like Insect Plague.
  229.  
  230.  
  231. Pathfinding:
  232. -- when doing pathfinding, at the start build up two movement
  233. profiles -- current and elective, with elective including
  234. all the monster's movement-enhancing effects. Assign the
  235. effects opportunity costs.
  236. We only need to calculate both paths for monsters whose
  237. current and elective profiles differ.
  238. -- If the elective path is much shorter, activate or prioritize
  239. the needed elective effects and use the elective path.
  240. -- When taking a step on an elective path:
  241. -- if you're beside terrain you need an elective effect to
  242. cross, activate the elective effect. If you can't, drop
  243. the path and redo the pathfinding.
  244. -- otherwise, take the step.
  245. -- When on an elective path, remember to unmark MS_INV_OKAY
  246. because betterFor changes based on demand for elective
  247. effects.
  248. -- Thus, monsters will put on levitation boots to cross chasms
  249. and fire boots to walk over magma, but they'll take the lev
  250. boots back off afterward because of the 50% move penalty.
  251.  
  252.  
  253. setContextActive
  254. -- Marks a Behavior as active that alters equipment betterFor
  255. based on context; EV_ISTARGET will be called at the start
  256. of every action to see if the
  257. -- So the monster uses the +4 sword usually, but uses the
  258. +1 flame sword when a target in LOS has flame vulnerability
  259. -- List InActive effects (equipment that is suboptimal in the
  260. generic context) in ListEffects() based on unworn inventory.
  261.  
  262.  
  263.  
  264. -- TT_MEMORY -- specific behaviors demand we remember
  265. things indefinitely, such as priests and altars,
  266. but we don't go to grab them right away.
  267.  
  268. Monsters need some way to remember the situation they're
  269. in, so they know to use, for example, wind wall if they've
  270. been shot with arrows five times in the last two turns.
  271. Brainstorm on this!
  272.  
  273.  
  274. STR_CASTER
  275. * Increase Avoid Melee Priority
  276. * Flee Based On Low Mana
  277. * Favor Ranged Magic to Inflict Damage, Summon, etc.
  278.  
  279. STR_BRUTE
  280.  
  281. STR_SKIRMISH
  282.  
  283. STR_SUPPORT
  284.  
  285. STR_BODYGUARD
  286.  
  287. STR_STRIKER // reprioritize, mobile, leave melee, address
  288. highest threats
  289.  
  290. STR_PACK // pack animals, wear down before attack, aid another, etc.
  291.  
  292. STR_OUTSIDER // powerful in melee, assorted innate powers
  293.  
  294. STR_
  295.  
  296.  
  297. */
  298.  
  299. Behavior "Fix Allies' Troubles" : BF_UNIVERSAL
  300. {
  301. Requires: BV_HAS_EFFS, BV_HAS_PARTY;
  302. On Event EV_THINK {
  303. hObj hAlly, hBAlly;
  304. int16 high, tr, htr, pri;
  305. if (EActor->hasEffToFix == 0)
  306. return NOTHING;
  307. hBAlly = NULL_OBJ; high = 0;
  308. for (hAlly=EActor->FirstAlly();hAlly;
  309. hAlly=EActor->NextAlly())
  310. if (hAlly->Troubles & EActor->hasEffToFix)
  311. for (tr=hAlly->FirstTrouble(e);tr;
  312. tr=hAlly->NextTrouble(e))
  313. {
  314. pri = tr / 256;
  315. if (pri > high) {
  316. hBAlly = hAlly;
  317. htr = tr % 256;
  318. high = pri;
  319. }
  320. }
  321. if (hBAlly == NULL_OBJ)
  322. return NOTHING;
  323. /* Don't try to fix Y's troubles when we're already running to X
  324. to
  325. fix HIS troubles. */
  326. if (high <= EActor->getMovementObjectivePri($"Fix Allies'
  327. Troubles"))
  328. return NOTHING;
  329. EActor->AddAct(ACT_CAST,high,EP_FIX_TROUBLE+(htr<<16));
  330. return NOTHING;
  331. };
  332. }
  333.  
  334. /* City watch and stuff -- ignore racial hostility and never initiate
  335. combat, stand in one location unless disturbed, return to that loc
  336. as soon as you have no targets, do not covet items. */
  337. Behavior "Guard Location"
  338. {
  339. Cancels: BV_TARGVIS, BV_INMELEE, BV_AFRAID;
  340. List:
  341. * NEGATE_BEHAVIORS
  342. $"Explore Dungeon"
  343. $"Wanderlust";
  344. On Event EV_THINK {
  345. int16 gx, gy;
  346.  
  347. /* If we haven't already been assigned a specific location on
  348. the
  349. map to guard when we were given the behavior, we guard the
  350. location we were first placed on the map at. */
  351. if (!EActor->hasEffStati(GENERIC,thID))
  352. EActor->GainPermStati(GENERIC,NULL_OBJ,SS_MONI,EActor->x
  353. +EActor->y*256);
  354.  
  355. gx = EActor->getEffStatiVal(GENERIC,thID) % 256;
  356. gy = EActor->getEffStatiVal(GENERIC,thID) / 256)
  357.  
  358. if (EActor->x == gx && EActor->y == gy)
  359. {
  360. EActor->AddAct(ACT_WAIT, PRI_NORMAL, 10);
  361. return NOTHING;
  362. }
  363.  
  364. if (EActor->hasMoveObjFrom(thID,gx,gy))
  365. return NOTHING;
  366.  
  367. EActor->addMoveObj(gx,gy,PRI_NORMAL,-2,thID);
  368. EActor->AddAct(ACT_MOVE,PRI_NORMAL,0);
  369. return NOTHING;
  370. };
  371. }
  372.  
  373. /* Westley's Code -- I'm not sure what it's doing */
  374. #if 0
  375. Behavior "Coup-de-Grace Helpless Foes"
  376. {
  377. Cancels: BV_ENRAGED;
  378. On Event EV_THINK {
  379. int16 best; hObj bc, c;
  380. best = 0;
  381. for(i=0;i!=8;i++)
  382. for (c = m->FCreatureAt(EActor->x+DirX(i),EActor->y+DirY
  383. (i));c;
  384. c = m->NCreatureAt(EActor->x+DirX(i),EActor->y+DirY(i)))
  385. if (EActor->getHostility(c) > best &&
  386. XPercieves(c))
  387. {
  388. best = isHostileTo(c);
  389. bc = c;
  390. }
  391. if (bc) {
  392. if (bc->hasStati(SLEEPING) ||
  393. bc->hasStati(PARALYSIS,PARA_HELD) ||
  394. (bc->hasStati(STUCK) && bc->hasStati(PRONE)))
  395. AddAct(ACT_COUPDEGRACE,P_URGENT,bc);
  396. if (AttackMode() == S_BRAWL || ((onPlane() != bc->onPlane())
  397. &&
  398. (!inSlot(SL_WEAPON) || !inSlot(SL_WEAPON)->isMagic())))
  399. AddAct(ACT_NATTACK,P_URGENT,bc);
  400. else if (AttackMode() == S_MELEE)
  401. AddAct(ACT_WATTACK,P_URGENT,bc);
  402. }
  403. }
  404. #endif
  405.  
  406. Behavior "Recognize Unbeatable Foe"
  407. if (EActor->attackForms & EActor->getKnownImmunes(mtarg) ==
  408. EActor->attackForms)
  409. isUnbeatable = true;
  410.  
  411. Behavior "Cannot Beat MR"
  412. If you can't beat a target's MR,
  413. (1) attack other targets
  414. (2) buff for melee and fight melee
  415. (3) buff allies, act as support
  416.  
  417. Behavior "Evade Elevated Foe"
  418. -- foe is flying too high to hit, so go somewhere
  419. with a lower ceiling.
  420.  
  421. Behavior "Placate Unbeatable Foe"
  422. (1) try resolve conflict
  423. (2) decide if fleeing is viable
  424. (3) surrender or flee
  425. (4) or just avoid getting near and fight other things
  426.  
  427. Behavior "List Pseudo-Effects" // Trap EV_LIST_EFFECTS
  428. --or--
  429. Behavior "Use Healing Skill" // Done using ACT_CUSTOM
  430.  
  431. Behavior "Jump Toward Objective"
  432. Behavior "Teleport to Objective"
  433.  
  434. int16 Creature::getBuffDispelPriority()
  435. {
  436. bool isFullCaster =
  437. (getAbilLev(CA_SPELLCASTING)*110 > getCR()*100) &&
  438. getAbilLev(CA_SPELLCASTING) > 3;
  439. int16 activeBuffs = ...
  440.  
  441.  
  442. if (isFullCaster && activeBuffs >= 4 &&
  443. buffMana >= tMana() / 3)
  444. return P_EXTREME;
  445.  
  446. int16 myCheck, hisCheck, priorTries;
  447.  
  448. ...
  449.  
  450. }
  451.  
  452. Behavior "Dispel Enemy Buffs"
  453. {
  454. Requires: BV_EFFECTS;
  455. Purpose: EP_DISPEL;
  456. On Event EV_THINK {
  457. if (mtarg->hMana > 30 || mtarg->isPlayer())
  458. {
  459. int16 manaCost, buffCount, sl;
  460. static int16 slots[] = { SL_AMULET, SL_LRING, SL_RRING,
  461. SL_BRACERS, SL_READY, SL_WEAPON,
  462. SL_CLOAK, SL_GAUNTLETS, SL_HELM };
  463. sl = random(9);
  464. mtarg->getBuffInfo(&buffCount,&manaCost,NULL);
  465. if (buffCount && manaCost > 150 && !random(2))
  466. AddAct(ACT_CAST,P_OVERRIDE,mtarg,EP_DISPEL);
  467. else if (buffCount && manaCost > 80)
  468. AddAct(ACT_CAST,P_URGENT,mtarg,EP_DISPEL);
  469. else if (buffCount || (mtarg->inSlot(sl) &&
  470. mtarg->inSlot(sl)->isMagic() &&
  471. !mtarg->inSlot(sl)->hasStati(DISPELLED)))
  472. AddAct(ACT_CAST,P_MODERATE+random(2),mtarg,EP_DISPEL);
  473. }
  474. if (rtarg->hMana > 30 || rtarg->isPlayer())
  475. {
  476. int16 manaCost, buffCount, sl;
  477. static slots[] = { SL_AMULET, SL_LRING, SL_RRING,
  478. SL_BRACERS, SL_READY, SL_WEAPON,
  479. SL_CLOAK, SL_GAUNTLETS, SL_HELM };
  480. sl = random(9);
  481. rtarg->getBuffInfo(&buffCount,&manaCost,NULL);
  482. if (buffCount && manaCost > 150 && !random(2))
  483. AddAct(ACT_CAST,P_OVERRIDE,rtarg,EP_DISPEL);
  484. else if (buffCount && manaCost > 80)
  485. AddAct(ACT_CAST,P_URGENT,rtarg,EP_DISPEL);
  486. else if (buffCount || (rtarg->inSlot(sl) &&
  487. rtarg->inSlot(sl)->isMagic() &&
  488. !rtarg->inSlot(sl)->hasStati(DISPELLED)))
  489. AddAct(ACT_CAST,P_MODERATE+random(2),rtarg,EP_DISPEL);
  490. }
  491. };
  492. }
  493.  
  494. Behavior "Use Healing on Allies"
  495.  
  496. Behavior "Charge at Enemy"
  497.  
  498. Behavior "Tumble when Threatened"
  499.  
  500. Behavior "Use Spring Attack"
  501.  
  502. Behavior "Use Whirlwind Attack"
  503.  
  504. Behavior "Perform Great Blow" // include smite preference
  505.  
  506. Behavior "Dip Item in Fountain" // Trap EV_RATEITEM to appraise
  507. fountain when first seen
  508.  
  509. Behavior "Loot Chest" // set move obj, pick lock, try force, get
  510. items, not from your HOME_REGION
  511.  
  512. Behavior "Hide Tactically"
  513.  
  514. Behavior "Hide Whenever Possible"
  515.  
  516. Behavior "Get Out Of Bad Field" // pathfind out of radius
  517.  
  518. Behavior "Mine for Treasure"
  519.  
  520. Behavior "Use Turn/Command"
  521.  
  522. Behavior "Use Gate Ability"
  523.  
  524. Behavior "Buff Until Buffed"
  525. -- each specialist has a BUFF_LIST constant, scan it (FirstListItem
  526. ()?)
  527. and cast each spell we don't have. We might need a getBuffList()
  528. function hardcoded, and getBuffState(). Maybe a boolean flag isBuff
  529. in the KnownSpells Array?
  530. -- some buffs (stoneskin) should be very high priority when not up,
  531. but
  532. most others shuold only be cast when not in combat.
  533.  
  534. /* Some Metamagic Feats are handled in ListEffects by listing effects
  535. more than once, with the feats in question applied -- i.e., Warp
  536. Spell */
  537.  
  538. /* The Pathfinding Algorithm should occur at some stage of EV_THINK if
  539. there are any ACT_MOVE lines in the queue, and it will translate
  540. the
  541. ACT_MOVE into ACT_WALK or ACT_JUMP with a specific direction
  542. attached. */
  543.  
  544. /* The Orders Mechanism should have an ability to give behaviors with
  545. the
  546. BF_ORDER flag, or take them away. Player preferences should have a
  547. list
  548. of each such behavior with ALWAYS/NEVER/SMART for each as Default
  549. Orders. */
  550.  
  551. Behavior "Fight Defensively When Desperate"
  552.  
  553. Behavior "Fight Defensively Near Unbeatables"
  554.  
  555. Behavior "Bring Items to Leader"
  556.  
  557. Behavior "Use Shapeshifting"
  558.  
  559. Behavior "Situation Equipment Changes: Magma"
  560. Behavior "Situation Equipment Changes: Fighting Mages"
  561.  
  562. Behavior "Get Useful Items"
  563.  
  564. Behavior "Use Breath Weapon"
  565.  
  566. Behavior "Use Spit Weapon"
  567.  
  568. Behavior "Bull Rush Foe Over Bad Terrain"
  569.  
  570. Behavior "Use Disarm" / BV_MANIP -- fine manipulators
  571.  
  572. Behavior "Foil Pursuit"
  573.  
  574. Behavior "Escape/Subvert Grapple"
  575.  
  576. Behavior "Use Roar Attack"
  577.  
  578. Behavior "Use Thrown Weapon"
  579.  
  580. Behavior "Make Trip Attack"
  581.  
  582. Behavior "Sprint When Desperate"
  583.  
  584. Behavior "Choose Armor Level"
  585. // Trap EV_BETTER_FOR, mages don't wear armor, rangers wear light,
  586. etc.
  587.  
  588. Behavior "Masquerade as Human"
  589. // for dragons and such with a human form
  590.  
  591.  
  592. Behavior "Hide Under Object" // prevent movement out for most move
  593. priorities
  594.  
  595. Behavior "Hide In Water" // ditto
  596.  
  597. Behavior "Hide On Ceiling"
  598.  
  599. Behavior "Eat When Hungry"
  600.  
  601. Behavior "Eat Items" // Oozes
  602.  
  603. Behavior "Avoid Conflict to Recover Mana"
  604.  
  605. Behavior "Wander Around Home Region"
  606.  
  607. Behavior "Return to Home Region When Tired"
  608.  
  609. Behavior "Skirmish Tactics"
  610.  
  611. Behavior "Pursue But Avoid Combat" // until overmatched, animal packs
  612.  
  613. Behavior "Recruit Allies" // NPC's issue enlist requests, poach PC
  614. allies
  615.  
  616. Behavior "Intimidate Enemy"
  617.  
  618. Behavior "Resolve Conflict"
  619. // good vs. good/neutral
  620. // Animal Empathics vs. Animals
  621.  
  622. Behavior "Buy Service Spell to Fix Trouble"
  623.  
  624. Behavior "Surrender When Overmatched"
  625. // maybe just as a tag for the fear behavior to check for
  626.  
  627. Behavior "Explore Dungeon"
  628. // int32 memory flag of investigated panels, so you know
  629. where you haven't been.
  630.  
  631. Behavior "Distract and Hide"
  632.  
  633. Behavior "Stay Mounted"
  634. // summon or recruit mount if you don't have one
  635. // remount when dismounted
  636.  
  637. Behavior "Climb on Ceiling"
  638.  
  639. Behavior "Jump over Trap/Obstacle"
  640.  
  641. Behavior "Disarm Traps"
  642.  
  643. Behavior "Re-Arm/Salvage/Set Traps"
  644.  
  645. Behavior "Use Pick Pockets"
  646.  
  647. Behavior "Apply Poison to Weapons"
  648.  
  649. Behavior "Flank For Rogue Ally"
  650.  
  651. Behavior "Bodyguard Mage Ally"
  652.  
  653. Behavior "Aid Leader When in Melee"
  654.  
  655. Behavior "Attack Most Wounded Targets First"
  656.  
  657. Behavior "Adhere to Chivalry"
  658.  
  659. Behavior "Adhere to Good Alignment"
  660.  
  661. Behavior "Greet Strangers"
  662. // human neutrals approach you, give favorable/unfavorable gesture
  663.  
  664. Behavior "Emote as Animal"
  665. // animals walk up and nuzzle, lick, or growl/hiss
  666.  
  667. Behavior "Chatter Randomly"
  668. // if monster has periodic messages, show them; some might have
  669. // associated timeouts ("The myconid tends the fungus garden.")
  670.  
  671. Behavior "Betray Weakened Ally"
  672. // Chaotic Evil monsters will eject badly wounded ally from party
  673. // and become hostile to it.
  674.  
  675. Behavior "Challenge for Leadership"
  676.  
  677. Behavior "Rage When Challenged" // Barbarians
  678.  
  679. Behavior "Hold Formation"
  680.  
  681. Behavior "Travel Near Leader"
  682.  
  683. Behavior "Take Point"
  684.  
  685. Behavior "Buff Leader"
  686. /* When leader is player, ask (yn) if player wants the spell cast
  687. on them, or Yes/No/Always/Never and store the Always and Never
  688. results in stati. */
  689.  
  690. Behavior "Buff Allies"
  691.  
  692. Behavior "Buff Weapon" // Greater Magic Weapon, etc.
  693.  
  694. Behavior "Buff Armor"
  695.  
  696. Behavior "Buff Allies' Weapons"
  697.  
  698. Behavior "Buff Allies' Armor"
  699.  
  700. Behavior "Cast Specific Spell"
  701. // pseudo-behavior to get ally to cast a spell they know with a
  702. target and metamagic chosen by the player.
  703.  
  704. Behavior "Devour Corpses" // for orcs
  705.  
  706. Behavior "Weaken/Curse Strong Foe" // when group holding back
  707.  
  708. Behavior "Use Secondary Weapons"
  709. {
  710. Requires: BV_HANDS;
  711. Cancels: BV_AFRAID;
  712.  
  713. }
  714.  
  715. Behavior "Favor Defensive Equipment" : BF_CONTEXT
  716. {
  717. Requires: BV_HANDS, BV_CONTEXT_EQUIP;
  718. On Event EV_ISTARGET {
  719. return EActor->isDefensive();
  720. },
  721. EV_EVAL_ITEM<EE_POST> {
  722. e.eiDefenseVal *= 2;
  723. return NOTHING;
  724. },
  725. EV_WIELD, EV_TAKEOFF {
  726. EActor->StateFlags &= ~MS_INVEN_OK;
  727. return NOTHING;
  728. };
  729. }
  730.  
  731. Behavior "Take War Form" : BF_ABILITY
  732. {
  733. Cancels: BV_AFRAID;
  734. On Event EV_THINK {
  735. if (hasStati(SPEC_TIMEOUT,A_FORM))
  736. return NOTHING;
  737. if (EActor->mID == EActor->getForm(FORM_WAR))
  738. return NOTHING;
  739. if ((e.bvFlags & BV_INMELEE) ||
  740. (EActor->isThreatened() && e.aiDesperation >= P_HIGH))
  741. EActor->AddAct(ACT_SHIFT,P_HIGH,NULL,EActor->getForm
  742. (FORM_WAR));
  743. return NOTHING;
  744. },
  745. EV_ISTARGET {
  746. if (!EActor->hasAttk(A_FORM))
  747. return CANNOT_CAST_IT;
  748. if (EActor->getWarForm() == NULL_ID)
  749. return CANNOT_CAST_IT;
  750. return SHOULD_CAST_IT;
  751. };
  752. }
  753.  
  754. Behavior "Take Disguise Form" : BF_ABILITY
  755. {
  756. Cancels: BV_TARGVIS, BV_INMELEE, BV_ENRAGED, BV_AFRAID;
  757. On Event EV_THINK {
  758. if (hasStati(SPEC_TIMEOUT,A_FORM))
  759. return NOTHING;
  760. if (EActor->mID == EActor->getForm(FORM_DISGUISE1) ||
  761. EActor->mID == EActor->getForm(FORM_DISGUISE2))
  762. return NOTHING;
  763. EActor->AddAct(ACT_SHIFT,P_HIGH,NULL,random(3) ?
  764. EActor->getForm(FORM_DISGUISE1) : EActor->getForm
  765. (FORM_DISGUISE2));
  766. return NOTHING;
  767. },
  768. EV_ISTARGET {
  769. if (!EActor->hasAttk(A_FORM))
  770. return CANNOT_CAST_IT;
  771. if (EActor->getForm(FORM_DISGUISE1) == NULL_ID)
  772. return CANNOT_CAST_IT;
  773. return SHOULD_CAST_IT;
  774. };
  775. }
  776.  
  777. Behavior "Take Fleeing Form" : BF_ABILITY
  778. {
  779. Requires: BV_AFRAID;
  780. Cancels: BV_INMELEE, BV_ENRAGED;
  781. On Event EV_THINK {
  782. if (hasStati(SPEC_TIMEOUT,A_FORM))
  783. return NOTHING;
  784. if (EActor->mID == EActor->getForm(FORM_FLEEING))
  785. return NOTHING;
  786. EActor->AddAct(ACT_SHIFT,P_HIGH,NULL,EActor->getForm
  787. (FORM_FLEEING));
  788. return NOTHING;
  789. },
  790. EV_ISTARGET {
  791. if (!EActor->hasAttk(A_FORM))
  792. return CANNOT_CAST_IT;
  793. if (EActor->getForm(FORM_FLEEING) == NULL_ID)
  794. return CANNOT_CAST_IT;
  795. return SHOULD_CAST_IT;
  796. };
  797. }
  798.  
  799. Behavior "Take Social Form" : BF_ABILITY
  800. {
  801. Cancels: BV_INMELEE, BV_ENRAGED, BV_AFRAID, BV_TARGVIS;
  802. On Event EV_THINK {
  803. if (hasStati(SPEC_TIMEOUT,A_FORM))
  804. return NOTHING;
  805. if (EActor->mID == EActor->getForm(FORM_SOCIAL))
  806. return NOTHING;
  807. if (there's a neutral or player nearby)
  808. EActor->AddAct(ACT_SHIFT,P_HIGH,NULL,EActor->getForm
  809. (FORM_SOCIAL));
  810. return NOTHING;
  811. },
  812. EV_ISTARGET {
  813. if (!EActor->hasAttk(A_FORM))
  814. return CANNOT_CAST_IT;
  815. if (EActor->getForm(FORM_SOCIAL) == NULL_ID)
  816. return CANNOT_CAST_IT;
  817. return SHOULD_CAST_IT;
  818. };
  819. }
  820.  
  821. Behavior "Take Terrain-Capable Form" : BF_ABILITY|BF_MOVEMENT
  822. {
  823. Cancels: BV_INMELEE, BV_ENRAGED;
  824. On Event EV_THINK {
  825. if (hasStati(SPEC_TIMEOUT,A_FORM))
  826. return NOTHING;
  827. if (EActor->isBadTerrainAt(e.EXVal,e.EYVal))
  828. if (EActor->getBestFormForTerrainAt(e.EXVal, e.EYVal))
  829. Actor->AddTravelAct(ACT_SHIFT,P_HIGH,NULL,EActor-
  830. >getBestFormForTerrainAt(e.EXVal, e.EYVal));
  831. return NOTHING;
  832. },
  833. EV_ISTARGET {
  834. if (!EActor->hasAttk(A_FORM))
  835. return CANNOT_CAST_IT;
  836. return SHOULD_CAST_IT;
  837. };
  838. }
  839.  
  840. Behavior "Phase Before Attacking" : BF_ABILITY|BF_EFFECTS
  841. {
  842. On Event EV_PERFORM_ACT {
  843. int16 sl;
  844. if (e.vAct != ACT_WATTACK ||
  845. e.vAct != ACT_NATTACK ||
  846. e.vAct != ACT_RATTACK)
  847. return NOTHING;
  848. if (EActor->onPlane() == EVictim->onPlane())
  849. return NOTHING;
  850. if (e.vAct == ACT_WATTACK)
  851. if (EActor->inSlot(SL_WEAPON) != NULL_OBJ)
  852. if (EActor->inSlot(SL_WEAPON)->hasQuality(WQ_GHOST_TOUCH))
  853. return NOTHING;
  854. if (e.vAct == ACT_RATTACK) {
  855. sl = EActor->isCharacter() ? SL_WEAPON : SL_ARCHERY;
  856. if (EActor->inSlot(sl) != NULL_OBJ)
  857. if (EActor->inSlot(sl)->hasQuality(WQ_GHOST_TOUCH))
  858. return NOTHING;
  859. }
  860. EActor->RedirectAct(ACT_PHASE,NULL,EVictim->onPlane());
  861. return DONE;
  862. },
  863. EV_ISTARGET {
  864. if (EActor->hasAbility(CA_PHASE))
  865. return SHOULD_CAST_IT;
  866. if (EActor->hasEffFor & EP_PHASE)
  867. return SHOULD_CAST_IT;
  868. return CANNOT_CAST_IT;
  869. };
  870. }
  871.  
  872. Behavior "Phase In Before Casting"
  873. ...
  874.  
  875. Behavior "Phase To Flee/Hide"
  876. {
  877. Requires: BV_AFRAID, BV_HIDDEN;
  878. On Event EV_THINK {
  879. if (EActor->onPlane() == EMap->getBasePlane())
  880. if (!EActor->hasStati(SPEC_TIMEOUT,CA_PHASE))
  881. EActor->AddAct(ACT_PHASE,NULL,-1); // any plane but this
  882. one!
  883. return NOTHING;
  884. },
  885. EV_ISTARGET {
  886. if (EActor->hasAbility(CA_PHASE))
  887. return SHOULD_CAST_IT;
  888. if (EActor->hasEffFor & EP_PHASE)
  889. return SHOULD_CAST_IT;
  890. return CANNOT_CAST_IT;
  891. };
  892. }
  893.  
  894. /* Creatures that live on other planes, like the ethereal filcher,
  895. should go back there when left alone. Characters with phasing
  896. spells or gear should hand out on the material unless given an
  897. order to do otherwise. */
  898. Behavior "Phase When Alone"
  899.  
  900. Behavior "Hide When Alone"
  901. {
  902. Cancels: BV_HIDDEN, BV_ILLUSION, BV_CHARGING, BV_TARGVIS;
  903. On Event EV_THINK {
  904. /* If we're desperate to get somewhere, we don't
  905. want to take the Hide movement penalty. */
  906. if (getMoveObjPri() > P_HIGH ||
  907. hasStati(SPRINTING))
  908. return NOTHING;
  909.  
  910. if (hasOrder("Hide;Order"))
  911. AddAct(ACT_HIDE,P_URGENT,NULL,HI_SHADOWS);
  912. else
  913. AddAct(ACT_HIDE,P_HIGH,NULL,HI_SHADOWS);
  914. return NOTHING;
  915. },
  916. EV_ISTARGET {
  917. if (EActor->hasSkill(SK_HIDE))
  918. return SHOULD_CAST_IT;
  919. return CANNOT_CAST_IT;
  920. };
  921. }
  922.  
  923. Behavior "Rate Shoreline Targets"
  924. /* When evaluating targets, non-amphibious aquatic monsters should
  925. only move toward targets that are in water, or or within one
  926. square of their body of water, or within two if they have reach. */
  927.  
  928. Behavior "Hide Underwater"
  929. {
  930. Prereq: BV_INWATER;
  931. Cancels: BV_ILLUSION, BV_CHARGING;
  932. On Event EV_THINK {
  933. if (hasStati(HIDING,HI_WATER))
  934. return NOTHING;
  935.  
  936. /* Hide only if there's no one around, or we're fleeing,
  937. possibly due to skirmish tactics -- so we can strike
  938. from underwater, swim away to hide and strike from
  939. surprise again and again. */
  940. if (e.bvFlags & BV_TARGVIS)
  941. if (!(e.bvFlags & BV_AFRAID))
  942. return NOTHING;
  943.  
  944. /* Check if water is too clear? If it obscures, we can
  945. hide in it an depth A, otherwise we need depth B. */
  946. if (!EActor->isWaterTerFlag(TC_OBSCURES))
  947. return NOTHING;
  948.  
  949. if (hasOrder("Hide;Order"))
  950. AddAct(ACT_HIDE,P_URGENT,NULL,HI_WATER);
  951. else
  952. AddAct(ACT_HIDE,P_HIGH,NULL,HI_WATER);
  953. return NOTHING;
  954. },
  955. EV_ISTARGET {
  956. if (EActor->hasSkill(SK_HIDE))
  957. return SHOULD_CAST_IT;
  958. return CANNOT_CAST_IT;
  959. };
  960. }
  961.  
  962. /* Spiders and such can hide under objects for a +10 circumstance
  963. bonus to Hide. When we do this, we want to not move unless the
  964. reason for moving is urgent. This is BF_LATE so we can cancel
  965. other actions that would disrupt our hiding.*/
  966. Behavior "Hide Under Objects" : BF_LATE
  967. {
  968. Cancels: BV_ILLUSION, BV_CHARGING;
  969. On Event EV_THINK {
  970. hObj hItem;
  971. if (hasStati(HIDING,HI_UNDER)) {
  972. /* Don't give ourselves away! */
  973. RemoveActBelowPri(ACT_MOVE,P_HIGH);
  974. RemoveActBelowPri(ACT_SHOOT,P_HIGH);
  975. RemoveActBelowPri(ACT_THROW,P_HIGH);
  976. RemoveActBelowPri(ACT_SATTACK,P_HIGH); // spit, breathe
  977. RemoveActBelowPri(ACT_CAST,P_MODERATE);
  978. return NOTHING;
  979. }
  980.  
  981. if (e.bvFlags & BV_TARGVIS)
  982. return NOTHING;
  983.  
  984. /* If this is a good spot to hide, do so. */
  985. for (hItem=EMap->FItemAt(x,y,li);hItem;
  986. hItem->EMap->NItemAt(x,y,li))
  987. if (hItem->getSize() >= getAttr(A_SIZ))
  988. {
  989. AddAct(ACT_HIDE,P_HIGH,NULL,HI_UNDER);
  990. return NOTHING;
  991. }
  992.  
  993. /* If there's a good hiding place within 5 squares,
  994. go there in order to hide. */
  995. if (!hasMoveObjFrom(thID))
  996. if (scanNearbyArea(thID,7))
  997. addMoveObjFromScan(P_HIGH,10,thID);
  998.  
  999. return NOTHING;
  1000. },
  1001. EV_EVALSPOT {
  1002. int16 xyli;
  1003. xyli = EMap->getEquivLI(x,y,li,e.EXVal,e.EYVal);
  1004. for (hItem=EMap->FItemAt(e.EXVal,e.EYVal,xyli);hItem;
  1005. hItem->EMap->NItemAt(x,y,xyli))
  1006. return P_HIGH;
  1007. return -1;
  1008. },
  1009. EV_ISTARGET {
  1010. return hasMFlag(M_HIDE_UNDER) ? SHOULD_CAST_IT : CANNOT_CAST_IT;
  1011. };
  1012. }
  1013.  
  1014. /* Darkmantles and other trappers hide on the ceiling. How
  1015. do they actually get up there? I haven't got a clue, and
  1016. neither does the player. In truth, they just "float" up
  1017. whenever the player can't see them, because anything else
  1018. is too difficult to code. So, only try to hide when TRULY
  1019. unseen, as opposed to "no target visible". */
  1020. Behavior "Hide On Ceiling" : BF_LATE
  1021. {
  1022. Cancels: BV_TARGVIS, BV_AFRAID, BV_CHARGING;
  1023. On Event EV_THINK {
  1024. hObj hItem;
  1025. if (hasStati(HIDING,HI_UNDER)) {
  1026. /* Don't give ourselves away! */
  1027. RemoveActBelowPri(ACT_MOVE,P_HIGH);
  1028. RemoveActBelowPri(ACT_SHOOT,P_HIGH);
  1029. RemoveActBelowPri(ACT_THROW,P_HIGH);
  1030. RemoveActBelowPri(ACT_SATTACK,P_HIGH); // spit, breathe
  1031. RemoveActBelowPri(ACT_CAST,P_MODERATE);
  1032. return NOTHING;
  1033. }
  1034.  
  1035. if (e.bvFlags & BV_TARGVIS)
  1036. return NOTHING;
  1037.  
  1038. if (!isUnseen())
  1039. return NOTHING;
  1040.  
  1041. AddAct(ACT_HIDE,P_HIGH,NULL,HI_CEILING);
  1042. },
  1043. EV_ISTARGET {
  1044. return hasMFlag(M_HIDE_ABOVE) ? SHOULD_CAST_IT : CANNOT_CAST_IT;
  1045. };
  1046. }
  1047.  
  1048. Behavior "Pickup Desired Items"
  1049. {
  1050. Prereq: BV_HANDS;
  1051. On Event EV_THINK {
  1052. int16 pri;
  1053. if (!hasTargOfType(TT_ITEM))
  1054. return NOTHING;
  1055. for (getFTargOfType(e,TT_ITEM);e.tsObj;
  1056. getNTargOfType(e,TT_ITEM)) {
  1057. pri = TargPriToActPri(e.tsPri)
  1058. if (e.tsObj->x == x && e.tsObj->y == y)
  1059. AddAct(ACT_PICKUP,pri,e.tsObj);
  1060. else if (p > P_MODERATE && !hasMoveObjFrom(e.tsObj))
  1061. addMoveObj(e.tsObj->x,e.tsObj->y,p-1,thID);
  1062. }
  1063. return NOTHING;
  1064. };
  1065. }
  1066.  
  1067. /* If our equipment selections aren't optimized, and we don't have
  1068. anything better to do, we should optimize them. */
  1069. Behavior "Optimize Inventory"
  1070. {
  1071. Prereq: BV_HANDS;
  1072. Cancels: BV_INMELEE;
  1073. On Event EV_THINK {
  1074. if (!(StateFlags & MS_INVEN_GOOD))
  1075. AddAct(ACT_EQUIP,P_MODERATE);
  1076. return NOTHING;
  1077. },
  1078. EV_ISTARGET {
  1079. if (hasMFlag(M_NOHANDS) || hasMFlag(M_MINDLESS))
  1080. return CANNOT_CAST_IT;
  1081. return SHOULD_CAST_IT;
  1082. };
  1083. }
  1084.  
  1085. Behavior "Buff Self"
  1086. {
  1087. Prereq: BV_EFFECTS;
  1088. Cancels: BV_ENRAGED;
  1089. Purpose: EP_BUFF;
  1090. On Event EV_THINK {
  1091. if (bvFlags & BV_INMELEE)
  1092. if (random(3)) {
  1093. AddAct(ACT_CAST,P_HIGH,NULL,EP_BUFF);
  1094. return NOTHING;
  1095. }
  1096. if (!longBuffsActive())
  1097. AddAct(ACT_CAST,P_URGENT,NULL,EP_BUFF);
  1098. if (hasShortBuffs() && getDesperation() >= P_HIGH)
  1099. AddAct(ACT_CAST,P_HIGH,NULL,EP_BUFF);
  1100. return NOTHING;
  1101. };
  1102. }
  1103.  
  1104. /* Later: Summon creatures into melee with oncoming people you
  1105. are avoiding melee with. Discern whether you're primarily
  1106. a brawler and shouldn't summon in melee, or of your summon
  1107. is strong enough for it to be worthwhile in melee. */
  1108. Behavior "Summon Aid"
  1109. {
  1110. Prereq: BV_EFFECTS;
  1111. Cancels: BV_ENRAGED;
  1112. Purpose: EP_SUMMON;
  1113. On Event EV_THINK {
  1114. if (getCurrPHD(PHD_MAGIC)*110 > getMaxPHD(PHD_MAGIC))
  1115. return NOTHING;
  1116. if (bvFlags & BV_INMELEE)
  1117. AddAct(ACT_CAST,P_LOW+random(4),mtarg,EP_SUMMON);
  1118. else
  1119. AddAct(ACT_CAST,P_LOW+random(4),rtarg,EP_SUMMON);
  1120. return NOTHING;
  1121. };
  1122. }
  1123.  
  1124. Behavior "Avoid Melee With Effects"
  1125. {
  1126. Prereq: BV_EFFECTS;
  1127. Cancels: BV_ENRAGED;
  1128. Purpose: EP_ESCAPE|EP_FOIL_PURSUIT;
  1129. On Event EV_THINK {
  1130. if ((bvFlags & BV_INMELEE) && (bvFlags & (BV_AFRAID|
  1131. BV_EVADING)))
  1132. AddAct(ACT_CAST,P_URGENT+random(3),mtarg,EP_ESCAPE);
  1133. else if (bvFlags & (BV_AFRAID|BV_EVADING)) {
  1134. for (getFTargOfType(e,TT_ENEMY);e.tsObj;
  1135. getNTargOfType(e,TT_ENEMY)) {
  1136. if (DistFrom(e.tsObj) < 3) {
  1137. AddAct(ACT_CAST,P_URGENT,e.tsObj,EP_FOIL_PURSUIT|
  1138. EP_ESCAPE);
  1139. }
  1140. }
  1141. }
  1142. };
  1143. }
  1144.  
  1145. /* Old Logic, need to update -- cast invis when not using normal
  1146. hide, but boost Hide only when hiding. */
  1147. Behavior "Aid Stealth With Effects" : BF_ORDER
  1148. {
  1149. Prereq: BV_EFFECTS;
  1150. Cancels: BV_ENRAGED, BV_TARGVIS;
  1151. Purpose: EP_STEALTH;
  1152. On Event EV_THINK {
  1153. /* Old:
  1154. if (isHiding && !isAfraid && rtarg && !isEnraged
  1155. && (dist(rtarg->x,rtarg->y,x,y) < 6) && !random(3))
  1156. AddAct(ACT_CAST,P_HIGH,rtarg,EP_STEALTH);
  1157. */
  1158. return NOTHING;
  1159. };
  1160.  
  1161. }
  1162.  
  1163. Behavior "Escape Grapple" : BF_ORDER
  1164. {
  1165. Prereq: BV_GRABBED;
  1166. Cancels: BV_ENRAGED;
  1167. On Event EV_THINK {
  1168. if ((bvFlags & BV_EVADING) || (!random(4)) ||
  1169. (getGrappler()->getAttr(A_STR) > (getAttr(A_STR)+5)))
  1170. AddAct(ACT_SATTACK,P_HIGH,NULL,A_ESCA);
  1171. return NOTHING;
  1172. },
  1173. EV_ISTARGET {
  1174. if (hasFeat(FT_MASTER_GRAPPLE) ||
  1175. hasAbil(CA_NATURAL_GRAB))
  1176. return CAN_CAST_IT;
  1177. return SHOULD_CAST_IT;
  1178. };
  1179. }
  1180.  
  1181. /* This is the logic behind whether a monster will use its
  1182. gate ability or not: it will only do so when facing another
  1183. monster 3 CRs higher then itself, or when facing a player
  1184. character (which, given the magic item christmas tree glow
  1185. effect, it's safe to assume smart monsters like demons and
  1186. celestials recognize). Monsters can only attempt to gate
  1187. once a day, hence the SPEC_TIMEOUT. */
  1188. Behavior "Use Gate Ability" : BF_ORDER
  1189. {
  1190. On Event EV_THINK {
  1191. if (bvDesperation >= PV_MODERATE)
  1192. if (!hasStati(SPEC_TIMEOUT,A_GATE))
  1193. AddAct(ACT_SATTACK,P_HIGH,mtarg ? mtarg : rtarg,A_GATE);
  1194. return NOTHING;
  1195. },
  1196. EV_ISTARGET {
  1197. return hasAttk(A_GATE) ? SHOULD_CAST_IT : CANNOT_CAST_IT;
  1198. };
  1199. }
  1200.  
  1201. bool Creature::canUseAttk(int16 at, Creature *targ)
  1202. {
  1203. // can't breathe when polyed human -- hasAttk checks this?
  1204. if (!hasAttk(at))
  1205. return false;
  1206. if (hasStati(SPEC_TIMEOUT,at))
  1207. return false;
  1208. if (hasStati(CANCELLED))
  1209. return false;
  1210. if (!targ)
  1211. return true;
  1212. if (knownImmune(targ,getAttk(at)->DType)
  1213. return false;
  1214. if (attkHitsAllies(at,targ))
  1215. if (!(isMType(MA_EVIL) && isMType(MA_CHAOTIC)))
  1216. return false;
  1217. // don't keep roaring if victim already frightened
  1218. if (isRedundantAttk(at,targ))
  1219. return;
  1220. if (dist(targ->x,targ->y,x,y) > getAttkRange(at))
  1221. return false;
  1222. return true;
  1223. }
  1224.  
  1225. Behavior "Use Breath/Spit Weapon" : BF_ORDER|BF_FORM
  1226. {
  1227. Requires: BV_TARGVIS;
  1228. On Event EV_THINK {
  1229. if (bvFlags & BV_INMELEE) {
  1230. if (canUseAttk(A_BREA,mtarg))
  1231. AddAct(ACT_SATTACK,P_URGENT,mtarg,A_BREA);
  1232. if (canUseAttk(A_BRE2,mtarg))
  1233. AddAct(ACT_SATTACK,P_URGENT,mtarg,A_BRE2);
  1234. if (canUseAttk(A_SPIT,mtarg))
  1235. AddAct(ACT_SATTACK,P_URGENT,mtarg,A_SPIT);
  1236. }
  1237. else if (rtarg) {
  1238. if (canUseAttk(A_BREA,rtarg))
  1239. AddAct(ACT_SATTACK,P_URGENT,rtarg,A_BREA);
  1240. if (canUseAttk(A_BRE2,rtarg))
  1241. AddAct(ACT_SATTACK,P_URGENT,rtarg,A_BRE2);
  1242. if (canUseAttk(A_SPIT,rtarg))
  1243. AddAct(ACT_SATTACK,P_URGENT,rtarg,A_SPIT);
  1244. }
  1245. return NOTHING;
  1246. },
  1247. EV_ISTARGET {
  1248. if (hasAttk(A_BREA) || hasAttk(A_BRE2) || hasAttk(A_SPIT))
  1249. return SHOULD_CAST_IT;
  1250. return CANNOT_CAST_IT;
  1251. };
  1252. }
  1253.  
  1254. Behavior "Use Sound Weapon" : BF_ORDER|BF_FORM
  1255. {
  1256. Requires: BV_TARGVIS;
  1257. On Event EV_THINK {
  1258. hObh hTarg; bool canUse;
  1259. if (!canUseAttk(A_ROAR))
  1260. return NOTHING;
  1261.  
  1262. canUse = false;
  1263. for (hTarg=getFTargetOfType(TT_ENEMY,e);hTarg;
  1264. hTarg=getNTargetOfType(TT_ENEMY,e))
  1265. if (canUseAttk(A_ROAR,e.tsObj))
  1266. canUse = true;
  1267.  
  1268. // later, consider fatigue, desperation, etc.
  1269. if (canUse)
  1270. AddAct(ACT_SATTACK,P_URGENT,NULL,A_ROAR);
  1271. return NOTHING;
  1272. },
  1273. EV_ISTARGET {
  1274. if (hasAttk(A_ROAR))
  1275. return SHOULD_CAST_IT;
  1276. return CANNOT_CAST_IT;
  1277. };
  1278. }
  1279.  
  1280. // yellow light, gas spore, etc.
  1281. Behavior "Kamakaze Explode Attack" : BF_ORDER|BF_FORM
  1282. {
  1283. Requires: BV_INMELEE;
  1284. On Event EV_THINK {
  1285. if (bvDesperation >= P_HIGH)
  1286. if (canUseAttk(A_EXPL))
  1287. AddAct(ACT_SATTACK,P_HIGH,mtarg,A_EXPL);
  1288. return NOTHING;
  1289. },
  1290. EV_ISTARGET {
  1291. return hasAttk(A_EXPL) ? SHOULD_CAST_IT : CANNOT_CAST_IT;
  1292. };
  1293. }
  1294.  
  1295. Behavior "Use Trip Attack" : BF_ORDER
  1296. {
  1297. Requires: BV_INMELEE, BV_HANDS, !BV_AFRAID, !BV_ENRAGED;
  1298. On Event EV_THINK {
  1299. int16 tripChance;
  1300. tripChance = 2;
  1301. if (inSlot(SL_WEAPON) && inSlot(SL_WEAPON)->HasIFlag
  1302. (WT_SUPER_TRIP))
  1303. tripChance += 20;
  1304. if (hasFeat(FT_MASTER_TRIP))
  1305. tripChance += tripChance + 30;
  1306. if (random(100) < tripChance)
  1307. AddAct(ACT_TRIP,P_HIGH,mtarg);
  1308. };
  1309. }
  1310.  
  1311. Behavior "Use Disarm Attack" : BF_ORDER
  1312. {
  1313. Requires: BV_INMELEE, BV_HANDS, !BV_AFRAID, !BV_ENRAGED;
  1314. On Event EV_THINK {
  1315. int16 disChance;
  1316. disChance = 2;
  1317. if (inSlot(SL_WEAPON) && inSlot(SL_WEAPON)->HasIFlag
  1318. (WT_SUPER_DISARM))
  1319. disChance += 20;
  1320. if (hasFeat(FT_MASTER_DISARM))
  1321. disChance += disChance + 30;
  1322. if (random(100) < disChance)
  1323. AddAct(ACT_DISARM,P_HIGH,mtarg);
  1324. };
  1325. }
  1326.  
  1327. /* Later, archery-based coup-de-grace */
  1328. Behavior "Use Coup de Grace" : BF_ORDER
  1329. {
  1330. Requires: BV_INMELEE, BV_HANDS, !BV_AFRAID, !BV_ENRAGED;
  1331. On Event EV_THINK {
  1332. hObj hTarg;
  1333. if (!inSlot(SL_WEAPON))
  1334. return NOTHING;
  1335. for (hTarg=getFTargetOfType(TT_ENEMY,e);hTarg;
  1336. hTarg=getNTargetOfType(TT_ENEMY,e))
  1337. if (hTarg->isHelpless() && isBeside(hTarg) && !knownImmune
  1338. (hTarg,AD_CRIT))
  1339. AddAct(ACT_COUP, P_URGENT, hTarg);
  1340. return NOTHING;
  1341. };
  1342. }
  1343.  
  1344.  
  1345. int16 MonsterBrain::calcTacticalBlastPoint(rID effID, Creature *targ)
  1346. {
  1347. int16 range = getRange(), rat, best, bhits, hits;
  1348. bool isGood = isMType(MA_GOOD);
  1349. bool isChaoticEvil = isMType(MA_EVIL) && isMType(MA_CHAOTIC);
  1350. OArray<Creature*,20,20> Allies, Enemies;
  1351.  
  1352. MapIterate(m,cr,i)
  1353. if (cr->isCreature() && !m->isSolidAt(cr->x,cr->y,cr->li) &&
  1354. dist(cr->x,cy->y,x,y) < range*2-1) {
  1355. if (cr->getGroupInfo() == getGroupInfo())
  1356. Allies.Add(cr);
  1357. else if (cr->isHostileTo(this))
  1358. Enemies.Add(cr);
  1359. else if (isMType(MA_GOOD) && cr->isMType(MA_SAPIENT))
  1360. Allies.Add(cr);
  1361. }
  1362. brat = -10000000;
  1363. for (xx=targ->x-range;xx<=targ->x+range;xx++)
  1364. for (yy=targ->y-range;yy<=targ->y+range;yy++)
  1365. if (m->InBounds(xx,yy)
  1366. {
  1367. hitEnemy = hitAlly = hitSelf = 0;
  1368. foreach(Allies)
  1369. if (dist(x,y,xx,yy) <= range)
  1370. hitAlly++;
  1371. foreach(Enemies)
  1372. if (dist(x,y,xx,yy) <= range)
  1373. hitEnemy++;
  1374. if (dist(x,y,xx,yy) <= range)
  1375. hitSelf++;
  1376.  
  1377. if (isGood)
  1378. rat = hitEnemy - hitAlly*1000 - hitSelf*2;
  1379. else if (isChaoticEvil)
  1380. rat = hitEnemy - hitAlly - hitSelf*1000;
  1381. else
  1382. rat = hitEnemy - hitAlly*5 - hitSelf*1000;
  1383. if (rat > brat)
  1384. { brat = rat; best = xx+yy*256; }
  1385. }
  1386. return brat > 0 ? best : -1;
  1387. }
  1388.  
  1389. bool isBullRushWise(hObj hMe, hObj hTarg)
  1390. {
  1391. int16 me, targ;
  1392. me = hMe->getAttr(A_STR) + hMe->hasFeat(FT_MASTER_BULL_RUSH)*7 +
  1393. hMe->getAttr(A_SIZ)*5;
  1394. targ = hTarg->getAttr(A_STR) + hTarg->getAttr(A_SIZ)*5+
  1395. hTarg->getAbilLev(CA_STABILITY)*4+
  1396. hTarg->ResistLevel(AD_KNOC)*3;
  1397. return me >= targ;
  1398. }
  1399.  
  1400. /* Later, use force bolt and gust of wind likewise
  1401. /* Later, scan all melee targets */
  1402. Behavior "Bull Rush Enemies Onto Bad Terrain"
  1403. {
  1404. Prereq: !BV_AFRAID, !BV_EVADING, BV_INMELEE, !BV_ENRAGED;
  1405. On Event EV_THINK {
  1406. int16 d, tx, ty, tx2, ty2;
  1407. d = DirTo(mtarg);
  1408. tx = mtarg->x + DirX(d);
  1409. ty = mtarg->y + DirY(d);
  1410. tx2 = mtarg->x + DirX(d)*2;
  1411. ty2 = mtarg->y + DirY(d)*2;
  1412. if (EMap->getWarnAt(tx,ty) || EMap->getWarnAt(tx2,ty2))
  1413. if (EMap->isPBadSquareFor(EActor,mtarg,tx,ty) ||
  1414. EMap->isPBadSquareFor(EActor,mtarg,tx2,ty2))
  1415. if (isBullRushWise(this,mtarg))
  1416. AddAct(ACT_SATTACK,P_URGENT,mtarg,A_BULL);
  1417. },
  1418. EV_ISTARGET {
  1419. return (EActor->getAttr(A_STR) > 14 && !EActor->isSessile()) ?
  1420. SHOULD_CAST_IT : CAN_CAST_IT;
  1421. };
  1422. }
  1423.  
  1424. /* Scan targets for incorporeality. If so:
  1425. * if you've got force damage, use it
  1426. * if you can, use Manifestation
  1427. * if you've got ki strike, everything's good
  1428. * if you've got a holy weapon and they're evil,
  1429. everything's good
  1430. * phase to meet them when in melee, if possible
  1431. * setEquipContext(thID) to equip ghost touch, etc.
  1432. * Drink potions of faerie if you got em
  1433. * If you can't fight, evade these creatures specifically
  1434. with a new movement objective
  1435. */
  1436. Behavior "Cope With Incorporeality"
  1437.  
  1438.  
  1439. Behavior "Make Melee Attacks"
  1440. {
  1441. Prereq: BV_INMELEE, !BV_AFRAID;
  1442. On Event EV_THINK {
  1443. hObj hWep;
  1444. hWep = inVSlot(SL_WEAPON);
  1445.  
  1446. if (bvFlags & BV_ENRAGED)
  1447. if (getStatiObj(ENRAGED) != mtarg) {
  1448. if (isBeside(getStatiObj(ENRAGED)))
  1449. mtarg = getStatiObj(ENRAGED);
  1450. else
  1451. return NOTHING;
  1452. }
  1453.  
  1454. if (hWep && !hWep->hasIFlag(WT_NO_MELEE)) {
  1455. /* When fighting incorporeals, fight with melee weapons by
  1456. preference
  1457. if we have ghost touch, but only hit with magical weapons
  1458. (==5% chance
  1459. to strike true per plus) if we don't have any better
  1460. option.
  1461. TODO: Check for holy weapon vs. evil, etc. */
  1462. if ((onPlane() == mtarg->onPlane()) || hWep->hasQuality
  1463. (IQ_GHOST_TOUCH) ||
  1464. hasStati(MANIFEST))
  1465. AddAct(ACT_WATTACK,P_HIGH,mtarg);
  1466. else if (hWep->getPlus() > 0)
  1467. AddAct(ACT_WATTACK,P_LOW,mtarg);
  1468. }
  1469.  
  1470. if (hWep == NULL_OBJ)
  1471. if ((onPlane() == mtarg->onPlane()) || hasAbility
  1472. (CA_KI_STRIKE) ||
  1473. hasStati(MANIFEST))
  1474. AddAct(ACT_NATTACK,P_HIGH,mtarg);
  1475.  
  1476. /* LATER, tweak the priority here to depend on strategy, among
  1477. other things.
  1478. Maybe we need some functions specifically to adjust
  1479. priorities based on
  1480. strategy. */
  1481. if ((hasEffFor & EP_BLAST) && !(bvFlags & BV_ENRAGED))
  1482. AddAct(ACT_EFFECT,P_URGENT,mtarg,EP_BLAST,CAST_INNATE_ONLY|
  1483. CAST_NO_AOO_ONLY);
  1484.  
  1485. return NOTHING;
  1486. };
  1487. }
  1488.  
  1489. Behavior "Make Archery Attacks" : BF_INVEN
  1490. {
  1491. Prereq: !BV_INMELEE, !BV_AFRAID, BV_TARGVIS, !BV_ENRAGED;
  1492. On Event EV_THINK {
  1493. hObj hBow;
  1494. hBow = isAdvancedInv() ? inVSlot(SL_WEAPON) : inVSlot
  1495. (SL_ARCHERY);
  1496.  
  1497. if (hBow && hBow->isType(T_BOW))
  1498. if (EMap->LineOfFire(this,rtarg)) {
  1499. if (it->needsToBeCocked())
  1500. AddAct(ACT_LOADXBOW,P_MODERATE,hBow);
  1501. else {
  1502. AddAct(ACT_RATTACK,P_HIGH,rtarg);
  1503. }
  1504. }
  1505. return NOTHING;
  1506. },
  1507. EV_ISTARGET {
  1508. hObj hItem;
  1509. if (hasMFlag(M_NOHANDS))
  1510. return CANNOT_CAST_IT;
  1511. for (hItem=FirstInv();hItem;hItem=NextInv())
  1512. if (hItem->isType(T_BOW))
  1513. return SHOULD_CAST_IT;
  1514. return CAN_CAST_IT;
  1515. };
  1516. }
  1517.  
  1518. Behavior "Use Ranged Attack Effects"
  1519. {
  1520. Prereq: !BV_INMELEE, !BV_AFRAID, BV_TARGVIS, !BV_ENRAGED,
  1521. BV_EFFECTS;
  1522. Purpose: EP_BLAST|EP_CURSE;
  1523. On Event EV_THINK {
  1524. /* Later, prioritize by strategy... */
  1525. if (rtarg && EMap->LineOfSight(this,rtarg) &&
  1526. EMap->LineOfFire(this,rtarg))
  1527. AddAct(ACT_EFFECT,P_URGENT+random(2),rtarg,EP_ATTACK|
  1528. EP_CURSE);
  1529. return NOTHING;
  1530. };
  1531. }
  1532.  
  1533. Behavior "Use Thrown Weapons" : BF_INVEN
  1534. {
  1535. Prereq: !BV_AFRAID, !BV_ENRAGED, BV_HANDS, BV_TARGVIS;
  1536. On Event EV_THINK {
  1537. hObj hThrown, hTarg, hBest;
  1538. hTarg = rtarg ? rtarg : mtarg;
  1539. hBest = NULL_OBJ;
  1540. for(hThrown=FirstInv();hThrown;
  1541. hThrown=NextInv())
  1542. if (hThrown->isGroup(WG_THROWN))
  1543. if (hBest == NULL_OBJ ||
  1544. hThrown->isBetterVersus(hTarg,hBest))
  1545. hBest = hThrown;
  1546. if (hBest != NULL_OBJ)
  1547. AddAct(ACT_THROW,P_HIGH,hTarg,hBest);
  1548. return NOTHING;
  1549. },
  1550. EV_ISTARGET {
  1551. hObj hThrown;
  1552. for(hThrown=FirstInv();hThrown;
  1553. hThrown=NextInv())
  1554. if (hThrown->isGroup(WG_THROWN))
  1555. return SHOULD_CAST_IT;
  1556. return CANNOT_CAST_IT;
  1557. };
  1558. }
  1559.  
  1560. Behavior "Enraged Movement"
  1561. {
  1562. Prereq: BV_ENRAGED, !BV_SESSILE;
  1563. On Event EV_THINK {
  1564. if (!isBeside(getStatiObj(ENRAGED)))
  1565. AddAct(ACT_MOVE,P_EXTREME,getStatiObj(ENRAGED));
  1566. return NOTHING;
  1567. };
  1568. }
  1569.  
  1570. Behavior "Move To Melee"
  1571. {
  1572. Prereq: !BV_ENRAGED, !BV_INMELEE, !BV_MOUNT, !BV_EVADING, !
  1573. BV_SESSILE, BV_TARGVIS;
  1574. On Event EV_THINK {
  1575. /* Usually movement into melee is low priority, but sometimes
  1576. (1 in 5) it gets higher, so we always keep moving toward
  1577. the target. */
  1578. AddAct(ACT_MOVE,random(5) ? P_LOW : P_URGENT,rtarg);
  1579. return NOTHING;
  1580. };
  1581. }
  1582.  
  1583. Behavior "Move To Flee"
  1584. {
  1585. Prereq: BV_AFRAID, !BV_SESSILE;
  1586. On Event EV_THINK {
  1587. AddAct(ACT_MOVE,P_HIGH,NULL);
  1588. return NOTHING;
  1589. };
  1590. }
  1591.  
  1592. Behavior "Move To Avoid Melee"
  1593. {
  1594. Prereq: BV_EVADING, !BV_SESSILE, BV_TARGVIS;
  1595. On Event EV_THINK {
  1596. bool hasEff;
  1597. hasEff = (hasEffFor & EP_ESCAPE);
  1598. if (mtarg)
  1599. AddAct(ACT_MOVE,hasEff ? P_MODERATE :
  1600. P_EXTREME,mtarg,MOVE_AWAY);
  1601. else if (rtarg && DistFrom(rtarg) < getIdealRange(this))
  1602. AddAct(ACT_MOVE,hasEff ? P_LOW : P_HIGH,mtarg,MOVE_AWAY);
  1603. return NOTHING;
  1604. };
  1605. }
  1606.  
  1607.  
  1608. Behavior "Break Off Melee by XCR"
  1609. /* If total XCR of melee enemies is 1/5th the monster's,
  1610. and there's a target in sight you either really hate
  1611. or is more than 3x to total XCR of your melee opponents,
  1612. run from melee, suck up the AoOs and pursue the real
  1613. threat.
  1614. This often happens when the PC spams low-level monster
  1615. summoning spells to prevent enemies from moving forward.
  1616. Now they have to spam high-level summons. :)
  1617. */
  1618.  
  1619. Behavior "Leave Melee to Pursue Hated Target"
  1620.  
  1621. Behavior "Leave Summoned Melee to Pursue Summoner"
  1622.  
  1623. /* Animals will panic, and become hostile for a limited number
  1624. of turns, if other creatures step too close to them when they
  1625. are outside their natural environment. They don't do this if
  1626. they've had Animal Empathy (calm) or Calm Animals used on
  1627. them. */
  1628. Behavior "Panic When Approached"
  1629.  
  1630. Behavior "Offer Sacrifice at Altar"
  1631.  
  1632. Behavior "Melt Ice Terrain With Fire"
  1633. -- isTerOnPath($"Ice Wall",5)
  1634.  
  1635. Behavior "Collapse Wall Spell With Effects"
  1636.  
  1637. Behavior "Fly Over Barrier"
  1638.  
  1639. Behavior "Flee Down Stairs/Portal"
  1640. -- use getComparativeStrengthMod() in evaluating whether
  1641. to attack head on, use skirmish tactics, etc.
  1642.  
  1643.  
  1644. Behavior "Use Passwall Smartly"
  1645.  
  1646. Behavior "Counter Earth Meld"
  1647. -- avoid standing near walls, for one thing
  1648. -- prioritize EP_FOIL_ESCAPE strongly
  1649. -- use Rock to Mud, etc.
  1650. -- strike as hard as possible when melder is exposed,
  1651. try for one-hit kills
  1652.  
  1653. Behavior "Smash Altars of Enemy Gods"
  1654.  
  1655. Behavior "Attempt Altar Conversion"
  1656. -- only if Know(Theo) + FavorLev is high enough
  1657.  
  1658. Behavior "Talk To New People"
  1659. -- for aranea, and random others -- approach each person
  1660. you don't have a TRIED stati for this behavior/person
  1661. combo and use the greet action to chat with them, then
  1662. mark them as tried and continue. Move toward them with
  1663. a movement objective before chatting.
  1664.  
  1665. Behavior "Drink From Fountain"
  1666. -- walk toward and drink from a fountain if you have high
  1667. luck, are diseased or poisoned, are seriously XP drained
  1668. or what have you.
  1669.  
  1670. Behavior "Travel Via Fountain"
  1671. -- Oozes - anyone with M_AMORPH, really - can use a special
  1672. teleport-like effect to travel from fountain to fountain
  1673. on EV_DESCEND.
  1674.  
  1675. Behavior "Bodyguard"
  1676. -- Move to intercept, sprinting if necessary, any character
  1677. that approaches the protected creature.
  1678. -- Break off other activities to reach anyone attacking the
  1679. protected in melee, and use great blows, throws, spells
  1680. with knockback and bull rush to get them away.
  1681.  
  1682. /* Flying creatures with ranged attacks in areas with a high
  1683. (or no) ceiling should stay elevated and strike at ground-
  1684. bound creatures from above, where they can't fight back.
  1685. Only fly down to enter melee when all ranged attacks are
  1686. expended or timed out. Also, be reluctant to enter areas
  1687. with a lower ceiling to avoid losing the flight advantage. */
  1688. Behavior "Fly Intelligently"
  1689.  
  1690. /* Behavior for Maeve's creatures -- be hostile to ugly or
  1691. repellent creatures, in order to test the ability of
  1692. behaviors to modify target system hostility rules. */
  1693. Behavior "Hostile to Uglyness"
  1694.  
  1695. Behavior "Pray For Aid"
  1696.  
  1697. Behavior "Seek, Tame and Ride Mount"
  1698.  
  1699. /*
  1700. -- count total enemies in LineOfFire by iterating targets
  1701. -- choose priority by counting enemies
  1702. -- determine how many enemies would still have LOF if the
  1703. wall was cast in each of the four cardinal directions
  1704. -- cast in whichever direction comes closest to dividing
  1705. the enemies exactly in half
  1706. -- if every direction is all-or-nothing, do not cast
  1707. */
  1708. Behavior "Use Wall Spell to Divide Enemies"
  1709.  
  1710. Behavior "Block Casters' Line-of-Sight"
  1711. -- use darkness, obscurement, call light, cause blindness,
  1712. wall of fog, etc.
  1713.  
  1714. Behavior "Use Wind Wall Against Archers"
  1715.  
  1716. Behavior "Use Wall Spell To Gain Buff Time"
  1717.  
  1718. /* When an enemy target has getRecentMoveVector() pointed away
  1719. from you -- either fleeing or avoiding melee, doesn't matter
  1720. -- and he's faster than you:
  1721. (1) cast EP_FOIL_PURSUIT effects
  1722. (2) throw tanglefoot bags
  1723. (3) try to blind or slow him at range
  1724. (4) sprint, if it makes you fast enough
  1725. (5) choose a different target rather than chasing */
  1726. Behavior "Handle Fast Escaping Target"
  1727.  
  1728. AI Targetting:
  1729. Okay, so over the last week I've been putting in a lot
  1730. of work recoding the monster targeting system -- the
  1731. code that decides what they consider hostile or allied
  1732. and how they prioritize those targets. I'm hoping to
  1733. move much farther along on this task -- maybe finish --
  1734. over the weekend.
  1735.  
  1736. There will be three major benefits of this. First and
  1737. foremost, I'll understand the code a lot better. It was
  1738. refactored once by Westley Weimer, and while he did
  1739. a great job I never clearly understood everything. Now
  1740. I know it in and out, so I'll be able to fix persistant bugs;
  1741. my list includes:
  1742. * NPCs hostile to your mount
  1743. * "hostile, formerly peaceful" after Quell
  1744. * Mara's hostile Mourners
  1745. * Your mount hostile to you.
  1746. * Fighting among your allies
  1747. * Monsters neutrals to you attacking your allies
  1748. The recoding should make several of these issues
  1749. irrelevant and obsolete, and the rest easy to fix. I welcome
  1750. reminders from people here for anything else that belongs
  1751. on this list.
  1752.  
  1753. The second major benefit is that the target system now
  1754. fits the overall source standards of the game, and is fully
  1755. accessable from IncursionScript -- the customization and
  1756. modularity stuff you hear me ranting so much about. The
  1757. final, and most interesting benefit, is that parties (groups
  1758. of allied creatures -- both your own and monster warbands)
  1759. are now much more manipulable as distinct entities. This
  1760. should alleviate some wierd situations (like the chieftan
  1761. being generated neutral and his troops hostile), and it will
  1762. also allow me to add a lot of fun flashy new features,
  1763. including:
  1764. * When you kill a group leader, the group decides on a
  1765. new leader, and can sometimes splinter in the process.
  1766. * When a leader is weakened, another monster can lead
  1767. a coup to try and take over a group, possibly splitting
  1768. it into two inimical factions.
  1769. * When you enlist a creature that another creature in your
  1770. group hates, that creature might quit your group over the
  1771. act, or otherwise react.
  1772. * Monsters willl be able to use the Enlist function to recruit
  1773. others to their group just the way the PC can (though they
  1774. can't enlist the PC, who is always the leader of his group).
  1775. * NPC spellcasters will be able to support their allies and
  1776. leader more sensibly, casting healing spells and such.
  1777. * The concept of "strain" will handle creatures snapping and
  1778. turning in a more nuanced manner, letting offenses build
  1779. up over time and making it less of an all or nothing issue.
  1780. * Monster CR and Charisma influences their level of influence
  1781. in their group, and how much "say" they have in what it is
  1782. and isn't hostile to.
  1783.  
  1784. The general design philosophy here is that in normal
  1785. circumstances hostility is determined on a whole-party
  1786. level. Thus, for example, a warband of 6 CE orcs and
  1787. one NG orc will all be hostile to the player, and a band
  1788. of 5 LG dwarves and one LE dwarf will all be neutral.
  1789. These averaged hostilities are calculated mathamatically
  1790. and are based on strength of animosity as well as
  1791. numbers. It's actually quite a fiddly, simulationist system,
  1792. because I like that kind of thing, even if all the detail isn't
  1793. visible at the surface level.
  1794.  
  1795. Creatures who would be neutral to your personally but
  1796. are hostile because of their party leaning (or vice versa)
  1797. will be noted as "reluctantly hostile" or "reluctantly neutral".
  1798. This will be useful for Semirath worshippers to spot the
  1799. good orcs they aren't supposed to kill, for example.
  1800.  
  1801. The question is when this "whole group hostility" system
  1802. should deviate. For example, if a player character charms
  1803. one member of a hostile band, the /charmed/ member
  1804. shouldn't stay hostile, nor should the entire group turn
  1805. friendly. What about Quell? Should it be limited to groups?
  1806. How "bad" are divided groups? I'm not sure it makes sense
  1807. to quell only part of an adventuring party and then have them
  1808. stand idly by while you slaughter the rest. If you Quell them,
  1809. should they be treated as having left the party?
  1810.  
  1811. Another confusing issue is the various "affect all monsters
  1812. of type N" conditions, such as elves' sylvan affinity (making
  1813. all animals neutral), a stone of undead warding, a ring of
  1814. aggrivate monster or Kysul's wrath effect. These things are
  1815. going to be causes of players running into half hostile, half
  1816. neutral. If an elf meets a bloodthirsty grey druid with his
  1817. animal companions, should the animals be hostile? What
  1818. if the druid is the PC and the elf the monster? Should animal
  1819. companions refuse to attack characters that have Animal
  1820. Friendship active? Should it add strain? I'm not sure what
  1821. the best way to deal with this is.
  1822.  
  1823. So I'm interested in any feedback from players about
  1824. anything I'm saying here. Specifically, I'm very enthused
  1825. with all the flash and simulationism of this, but I don't want
  1826. to let that get in the way of practicality. In other words,
  1827. what rules should I implement in the new target system
  1828. to avoid frusteration and keep players' blood pressure
  1829. under control? :)
  1830.  
  1831. ----
  1832.  
  1833. Tangentally, another major addition will be the Behaviour
  1834. system, which is essentially rule-based logic for monsters --
  1835. resources that modify how monsters act in certain situations,
  1836. when conditions are met. I'm brainstorming for different
  1837. Behaviours to add now, and welcome suggestions. A lot of
  1838. things currently hardcoded (like monsters fleeing or casters
  1839. avoiding melee) will become Behaviour resources. Further
  1840. ideas include:
  1841. * When monster has a vial of poison and Poison Use skill,
  1842. poison an unpoisoned, wielded weapon.
  1843. * Switch weapons contextually to attack players with the
  1844. weapons that hit observed "resistance holes". (Monsters
  1845. will have the ability to 'learn' weaknesses, but that has
  1846. nothing to do with behaviors.)
  1847. * Use Jump intelligently in combat if the monster has it as
  1848. a skill. Same with Turn Undead, Sprinting, Whirlwind
  1849. Attack, etc. -- behaviours make this kind of thing much
  1850. easier to "teach" the monsters to use.
  1851. * Kobolds will actally reset traps in the game. Likewise,
  1852. any monster with Handle Device might disarm them.
  1853. * Fleeing humanoid monsters will close and/or lock doors
  1854. to stop those they're fleeing from.
  1855. * Lawful monsters might spontaneously surrender rather
  1856. than fleeing when afraid, as requested.
  1857. * Monsters can initiate a revolt to try to take over their
  1858. group, as discussed above.
  1859. * Monsters can try to enlist other monsters, if they have
  1860. Diplomacy et al. Later same for Cow, Quell, etc. --
  1861. though obviously not against the player.
  1862. * Casters fire /dispel magic/ at heavily buffed creatures,
  1863. /shatter/ at characters with fragile equipment, Will save
  1864. spells at fighter types, Fort saves at spindly types,
  1865. /dimensional anchor/ at people they've seen teleport,
  1866. /dismissal/ at summoned creatures, etc. (Behaviours
  1867. were concieved with the "counter X with Y" mentality
  1868. and will make a lot of the very powerful magic in
  1869. Incursion more balanced).
  1870. * Monsters will flee, avoid melee or use only non-standard
  1871. attacks (wands, etc.) against a creature that is phased
  1872. or immune to their weapons.
  1873. * Monsters with Sneak Attack will move into flanking
  1874. positions, seek to stun the player, etc.
  1875. * Monsters being shot with arrows by creatures they can't
  1876. see will put up missile defense effects, flee away from
  1877. the direction the arrows are coming, etc.
  1878. * When chaotic and/or evil monsters surrender, they will
  1879. sometimes treacherously attack again afterward (at which
  1880. time they can be freely killed no matter what they do).
  1881. * Neutral monsters will react more positively to characters
  1882. who heal their wounds, cure diseases, etc.
  1883. * I'm also going to use behaviors to implement monster
  1884. actions with no game effect, just for flavor (The orc glares
  1885. at the elf. The horse eats grass. The human warrior paces.
  1886. The floating eye scans the vicinity. The gnome mage chats
  1887. with the human druid.)
  1888. * I'm debating adding the hunger mechanic for monsters,
  1889. especially beasts, but I worry about the player starving the
  1890. whole dungeon level to death by resting six or seven times
  1891. in a row. Don't know how I want to deal with this. Even if
  1892. not, monsters could still eat things even if they don't /have/
  1893. to in order to survive.
  1894. * This system will also allow custom plot-related behaviours
  1895. for select groups, like any surviving goblins in the goblin
  1896. camp becoming permanently afraid if you kill Murgash, just
  1897. because that's cinematic and badass.
  1898.  
  1899. I'm not saying I'm going to do all this stuff right away for
  1900. the next release -- I'll build up behavior lists over time, just
  1901. like I have with spells. But the cool part is that adding new
  1902. behaviors is as independant of the rest of the game as
  1903. adding new monsters or spells, which makes it really
  1904. flexible.
  1905.  
  1906. So basically I'm soliciting for suggestions from players for
  1907. things monsters (or a small or large subset thereof) could be
  1908. programmed to do, that people think would make the game
  1909. better.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement