Issuing orders to party members and refactoring AI...

posted in Caveman
Published September 11, 2014
Advertisement

Issuing orders to party members and refactoring AI...

NOTES:
1. in this article, any distances mentioned are in feet.
2. abbreviations used in the pseudocode:
"ret" = return
"dir" = direction
"loc" = location
"rh" = relative heading
"CR" = collision recovery

I've been playtesting the game at advanced stages, when you can control more than one band member. This means its time to implement giving orders to party members. The goal is to get the orders and AI to the point where the player, in control of one PC, and able to issue orders to some number of friendly NPCs, can stage an ambush of a target. This requires abilities like use stealth mode, goto location, use missile or hand weapons, attack on my signal, etc. After thinking about it for a while, and going through two design iterations i came up with:
.-----------------------------------------------------------Orders design, version 2.player presses orders hotkey ( default = 'O' )Give orders to...==============EveryoneParty member 1Party member 2Party member 3...Cancellist of party members is all band members, pets, warriors, and companions within 300 of player.Orders...=================goto - location (raypick)use stealth modeuse non-stealth modeuse hand wpn (and melee AI)use missile wpn (and skirmish AI)non-stealth attack (designated or default target)stealth attack (designated or default target)follow - someone (including player - pick list of party members)as you were - cancels ordersrun awaydesignate target (raypick)maintain distancewait here (goto location, location=here)Cancelraypick location: cast ray. location is where ray hits ground: IE when ray.y <= heightmap(ray.x,ray.z).raypick tgt: raypick location, then return closest badguy to that location.Follow.....==============Party member 1Party member 2Party member 3...Cancellist of party members is all band members, pets, warriors, and companions within 300 of player.--------------------------------------------
.
.
.

The original plan was to modify the AI as follows:
.if unit has orders, do orders // (perhaps with some special cases, like there is a badguy about to attack me)else do normal AI
.
.
.
So then i took a look at what the "normal" AI was. The normal AI was the original quick and dirty prototype AI, which has been modified and expanded until it actually handled over a dozen different types of AI. Its original form was:
.for each unit set target steer move attack
.
.
.
and inside set target, steer, move, and attack, it dealt with the many flavors of AI. On top of this, a setstate/runstate design had been placed, that set the state based on AI type, then called runstate, which made the actual calls to steer, move, attack, etc. Plastering orders on top of all this, and handling the special cases for orders sounded like i would be adding more bad design to existing bad design. Refactoring was called for. This was actually planned all along. the idea was to start with some quick and dirty AI, modify it as needed so its design evolved during development, and then refactor once its desired behavior had been pretty well determined. When i took a look at the exiting AI, i copied it (in pseudocode) into the todo list for the project, so i could get a better handle on what was there. Here's the basics of what i found:
.====== current AI =================================== Bandmember AI---------------------if badguys_near, if inshelter, leave shelter else if doing action, stop actionif not doing action setwpn if in collision recovery, do collision recovery and return set tgt steer move atkelse do action animal AI:----------------setstaterunstate setstate: ----------------if suprised avian, move suprised avian. state=stand, then calls runstate and returnselse if avian predator, avian predator setstateelse if resting, and not done resting, state=restelse if fatuigued, state=restif caveman, setwpnif running thief, thief run setstateelse if approaching thief, thief approach setstateelse if taking fire, taking fire setstateelse if defend location, defend location setstateelse if friendly, friendly setstateelse if hostile, hostile setsatateelse if companion, wartrior, or tamed: companion setstateelse if attack_AI, attack setstate (predators)else if maintain_distance_AI, maintain distance setstateelse if defend_AI, defend setstateelse all others setstate avian predator setstate:---------------------------------set tgt or rng&rhif halfdead, state=runawayelse if taking fire, taking fire setstateelse if resting, and not done resting, state=restelse if fatuigued, state=restelse if not attacking and has tgt within 20, save current state, state=attackelse if attacking but no tgt within 20, state=savestateelse if state=predator hunt if carcass nearby, state= eat kill else if no tgt, state=flockelse if state=predator eat if carcass nearby, state= eat kill else if no tgt, state=flockelse (grazing) if make check, state=predator hunt (time to go hunting!) thief run setstate----------------------if cornered, state=corneredelse if state=collision recovery, do nothingelse set tgt or rng state= thief run thief approach setstate----------------------if cornered, state=corneredelse if state=collision recovery, do nothingelse set tgt or rng state= thief approach taking fire setstate-------------------------if cornered, state=corneredelse if state=collision recovery, do nothingelse set tgt or rng if animal is leaving, do nothing else if tgt is bandmember up a tree and make check, leave else if has tgt if halfdead, state=runaway else state=attackelse state=flock defend location setstate--------------------------------if cornered, state=corneredelse if state=collision recovery, do nothingelse set tgt or rng state=attack tgt closest to location friendly setstate----------------------------if cornered, state=corneredelse if state=collision recovery, do nothingelse set tgt or rng if talking to bandmember, state=stand else if CRH caveman (a caveman at a shelter) if within 500 of home if >50 to home, moveto home else if has tgt <50 from home, attack else graze else if has tgt, attack else graze hostile setstate-----------------------if cornered, state=corneredelse if state=collision recovery, do nothingelse set tgt or rng state=attack companion setstate--------------------------if cornered, state=corneredelse if state=collision recovery, state=collision recovery (no change)else set tgt or rng if > 100 from ower,state= moveto owner else if has tgt, state=attack else if talking to bandmember, state=stand else if > 20 to owner, state=moveto owner else state=stand attack setstate (predators)--------------------------------------if cornered, state=corneredelse if state=collision recovery, state=collision recovery (no change)else set tgt or rng if animal is leaving, do nothing else if tgt is bandmember up a tree and make check, leave else if state=attack if has tgt if halfdead, state=runaway else if tgt rng >20 flock else (no tgt) state=flock else if state=predator hunt if has tgt if halfdead, state=runaway else if carcass nearby, state=eat kill else (no tgt) if halfdead, state=runaway else if carcass nearby, state=eat kill else state=flock else if state=eat if has tgt if halfdead, state=runaway else if rng<20 state=attack else (no tgt within 20) if carcass nearby, state=eat kill else state=flock else (no tgt) if carcass nearby, state=eat kill else state=flock else if has tgt if halfdead, state=run away else if tgt <20 state=attack else graze else graze if make check, state=predator hunt maintain distance setstate----------------------------------if cornered, state=corneredelse if state=collision recovery, state=collision recovery (no change)else set tgt or rng if halfdead, state=run away else graze defend setstate---------------------- if cornered, state=corneredelse if state=collision recovery, state=collision recovery (no change)else set tgt or rng if has tgt if halfdead, state=run away else if tgt<20, state=attack else graze else graze all others setstate-------------------------if cornered, state=corneredelse if state=collision recovery, state=collision recovery (no change)else set tgt or rng if tgt is bandmember up a tree and make check, state=leave if state=leave, do nothing else state=attack graze---------state periodically transitions between stand, wander, and flock, at random. set tgt--------------------if caveman if thief, tgt=current bandmember else if defend location, set hostile tgt defloc else if hostile, set hostile tgt else if freindly, set friendfdly tgt else if warrior or companion, set tamed tgtelse (animal) if defend location, set wild tgt defloc if wild if state=predator hunt, set predator tgt else set wild tgt else if subdued or captured, set wild tgt else if tamed, set tamed target set hotile tgt defend location--------------------------------------targets the detected bandmember, non hostile animal, not subdued animal, or not captured animal which is closest to the location to defend. set hostile tgt--------------------targets the closest:detected bandmember, not obscured by coverage due to range- or -non hostile, non subdued, non captured animal, not obscured by coverage due to range set friendly tgt--------------------targets closest:wild or hostile, not obscured by coverage due to range set tamed tgt-----------------------if rng to owner > 20, tgt=ownerelse tgt=set friendly tgt (closest wild or hostile, not obscured by coverage diue to range)if tgt rng to owner > 20, tgt= none set wild tgt defend location-----------------------------------targets closest to defend location:detected bandmember-or-not subdued or captured animal, not of same type as attacker. set wild target----------------------targets closest:detected bandmember, not obscured by coverage due to range-or-not subdued or captured animal, not of same type as attacker, not obscured by coverage due to range set predator tgt---------------------targets closest:detected bandmember, not obscured by coverage due to range, if a baseline caveman has same or less HP than attacker (predators dont target animal types with more hit points than the predator has)-or-not subdued or captured animal, not of same type as attacker, not obscured by coverage due to range, and has same or less HP than attacker (predators dont target animal types with more hit points than the predator has). runstate---------------if in collision recovery move_collision_recovery return stand: if avian if airborne, land else recover fatigueelse recover fatigue wander: (a "wander to" location is randomly generated and stored when this state is first entered)if avian, calc rel heading to wander to locationsteer_animal3moverun run away:steer_animal3moverundo_animal_atk attack, predator hunt:if avian, run avian attack AIelse calc heading set rng steer animal3 new_moveatk do_animal_atk eatkill:do eat kill cornered:do_cornered def loc:do def loc moveto home:do move to home friendly atk:calc headingset rngnew steer animalnew move animaldo animal atk thief approach:calc headingset rngnew steer animalnew move animalif rng<10 thief dialog (gimme all your stuff, or else!) thief run:steer animal3moverun rest:if airborne avian, landelse recover fatigue move to owner:set tgtcalc headingset rngnew steer animalnew move animal move_collision_recovery-----------------------------------calc amount to turn, and turn animalif animal facing generaly in desired direction, moverun increment collision recovery counter if counter >= limit, end collision recovery land----------move animalif alt<=0, alt=0 (they landed)else adjust angle of dive based on alt steer_animal3 - uses trinkets taken as desired heading---------------------------if avian if runaway, add 180 to desired heading turn_animal set pitch to climb else calc rng if behind and rng<50, do nothing (fly straight) else turn_animal climb_or_diveelse if runaway, add 180 to desired heading calc RelHeading turn based on R.H. moverun------------------set speed based on walking, running or sprintingcalc new locationif collision go into collision recoveryelse update location ========== end current AI =================
.
.
.
the original plan for refactoring was:
at the highest level, i wanted two routines: setstate and runstate.
at the lowest level, i also wanted two routines: turn(amount) and move(amount).
Great! Then it was just the stuff in between that i had to worry about.

So i pseudocoded a setstate/runstate version of the AI, improving the designed behavior at the same time. This wasn't that hard. setstate simply called a custom setstate routine for each of the types of AI, and runstate was largely unchanged. I also separated the avian from the non-avian runstates, as they do differ somewhat. I called the new AI api the "BB " api, hence the BB at the beginning of function names and predefined values.

Here's the result:
.int BBsetstate_common (returns state selected, or -1 for none selected)=========================if cornered, ret BB_ATTACKelse if in collision recovery, ret BB_COLLISION_RECOVERYelse if halfdead, ret BB_FLEEelse if badguy within 20 if badguy stronger, ret BB_FLEE else ret BB_ATTACKelse if taking fire if have tgt, ret BB_ATTACK else RET BB_FLOCKelse if resting ret BB_STANDelse ret -1 int BBsetstate_avian_common (returns state selected, or -1 for none selected)=========================if cornered, ret BB_AVIAN_ATTACKelse if in collision recovery, ret BB_AVIAN_COLLISION_RECOVERYelse if halfdead, ret BB_AVIAN_FLEEelse if badguy within 20 if badguy stronger, ret BB_AVIAN_FLEE else ret BB_AVIAN_ATTACKelse if taking fire if have tgt, ret BB_AVIAN_ATTACK else RET BB_AVIAN_FLOCKelse if resting ret BB_AVIAN_STANDelse ret -1 int BBsetstate_orders=============================set state based on the unit's orders int BBsetstate_avian_orders=============================set state based on the avian unit's orders int BBsetstate_graze=======================as current graze, adds migrate.outputs:BB_STANDBB_WANDERBB_FLOCKBB_MIGRATE int BBsetstate_avian_graze=======================as current graze, adds migrate.outputs:BB_AVIAN_STANDBB_AVIAN_WANDERBB_AVIAN_FLOCKBB_AVIAN_MIGRATE int BBsetstate_BM: (band members)========================if badguys near if in shelter setaction to leave shelter ret BB_DOACTION else if doing action, stop action if has orders, ret BBsetstate_orders else ret BB_ATTACKelse if has orders, ret BBsetstate_orderselse if doing action, ret BB_DOACTIONelse ret BB_STAND int BBsetstate_flunkey (pet land animals, warriors, and companions)=========================if far from owner, ret BB_MOVETO_OWNERelse if badguys near if has orders, ret BBsetstate_orders else ret BB_ATTACKelse if has orders, ret BBsetstate_orderselse if talking to BM, ret BB_STANDelse if >20 from owner, ret BB_MOVETO_OWNERelse ret BB_STAND int BBsetstate_avian_flunkey (pet avians)=========================if far from owner, ret BB_AVIAN_MOVETO_OWNERelse if badguys near if has orders, ret BBsetstate_avian_orders else ret BB_AVIAN_ATTACKelse if has orders, ret BBsetstate_avian_orderselse if talking to BM, ret BB_AVIAN_STANDelse if >20 from owner, ret BB_AVIAN_MOVETO_OWNERelse ret BB_AVIAN_STAND int BBsetstate_friendly (friendly cavemen)========================= if CRH caveman within 500 of home if >50 from home, ret BB_MOVETO_HOME else if badguys near home, ret BB_ATTACK else if talking to BM, ret BB_STAND else ret BBsetstate_grazeelse if badguys near, ret BB_ATTACK else if talking to BM, ret BB_STAND else ret BBsetstate_graze int BBsetstate_defloc (cavemen or land animals defending a location)==================if far from loc, ret BB_MOVETO_LOCelse if badguys near, ret BB_ATTACKelse ret BB_STAND int BBsetstate_hostile (hostile cavemen)============================if badguys near, ret BB_ATTACKelse ret BBsetstate_graze int BBsetstate_thief (thieves)===========================if in approach mode, ret_BB_THIEF_APPROACHelse ret BB_THIEF_RUN int BBsetstate_predator (wild land predators)=======================================================if hunting if carcass nearby, ret_BB_EATKILL else if has tgt, ret BB_HUNT else ret BB_FLOCKelse if eating if carcass nearby, ret BB_EATKILL else ret BB_FLOCKelse ret BB_FLOCK int BBsetstate_avian_predator (wild avian predators)=======================================================if hunting if carcass nearby, ret_BB_AVIAN_EATKILL else if has tgt, ret BB_AVIAN_HUNT else ret BB_AVIAN_FLOCKelse if eating if carcass nearby, ret BB_AVIAN_EATKILL else ret BB_AVIAN_FLOCKelse ret BB_AVIAN_FLOCK int BBsetstate_defend (wild land animals w/ defend AI)==============================if badguys near, ret BB_ATTACKelse ret BBsetstate_graze int BBsetstate_avian_defend (wild avians w/ defend AI)==============================if badguys near, ret BB_AVIAN_ATTACKelse ret BBsetstate_avian_graze int BBsetstate_maintain_distance (wild land animals)=========================if badguys near, ret BB_FLEEelse ret BBsetstate_graze int BBsetstate_avian_maintain_distance (wild avians)=========================if badguys near, ret BB_AVIAN_FLEEelse ret BBsetstate_avian_graze int BBsetstate (13 types of AI)==================================if avian result=BBsetstate_commonelse result=BBsetstate_avain_commomif result != -1 ret resultif BM, BBsetstate_BMelse if avian flunkey, BBsetstate_avian_flunkeyelse if flunkey, BBsetstate_flunkeyelse if friendly, BBsetstate_friendlyelse if defloc, BBsetstate_deflocelse if hostile, BBsetstate_hostileelse if thief, BBsetstate_thiefelse if avian_predator, BBsetstate_avian_predatorelse if predator, BBsetstate_predatorelse if avian_defend, BBsetstate_avian_defendelse if defend, BBsetstate_defendelse if avian_maintain_distance, BBsetstate_avian_maintain_distanceelse BBsetstate_maintain_distance BBrunstate (24 states)=============================BB_DOACTION do action modeBB_ATTACK, BB_HUNT: turn2tgt(closest badguy) if facing(closest badguy) run do attackBB_AVIAN_ATTACK, BB_AVIAN_HUNT: if tgt behind and rng<50 climb run else turn2tgt(closest badguy) set pitch run do attackBB_COLLSION_RECOVERY turn2dir(CR direction) if facing(CR direction) run inc CR counterBB_AVIAN_COLLSION_RECOVERY turn2dir(CR direction) climb run inc CR counterBB_FLEE turnfromtgt(closest badguy) runBB_AVIAN_FLEE turnfromtgt(closest badguy) climb runBB_FLOCK turn2tgt(leader) walkBB_AVIAN_FLOCK turn2tgt(leader) set pitch runBB_STAND recover fatigueBB_AVIAN_STAND if airborne, land else recover fatigueBB_MOVETO_OWNER turn2tgt(owner) runBB_AVIAN_MOVETO_OWNER turn2tgt(owner) set pitch runBB_WANDER turn2dir(wander dir) walkBB_AVIAN_WANDER turn2dir(wander dir) set pitch runBB_MIGRATE turn2dir(migrate dir) walkBB_AVIAN_MIGRATE turn2dir(migrate dir) set pitch runBB_MOVETO_LOC turn2loc(loc) if avian, set pitch runBB_EATKILL turn2tgt(closest carcass) if at carcass, eat else walkBB_AVIAN_EATKILL turn2tgt(closest carcass) set pitch if at carcass if airborne, land else eat else runBB_THIEF_APPROACH turn2tgt(player) run if at tgt, do dialogBB_THIEF_RUN turnfromtgt(player) run
.
.
.
Then it occured to me that the setstate/runstate pattern is sort of yet another example of unnecessary deferred processing. if i'm in setstate, and determine a desired state, right then i know which code in the case statement in runstate to run, so why not put the code in a routine and just call it right then and there? so the basic architecture of the AI evolved again. The follow is an example of the basic design iterations:
.ORIGINAL WAY:for each unit set tgt (based on unit type) steer (based on situation and AI type) move (based on situation and AI type) do attack (if badguy in strikezone, start attack)SETSTATE/RUNSTATE WAY:void setstate{if (condition A) state=Aelse if (condition B) state=B...}void runstate{switch(state)case A: // code to handle state A breakcase B: // code to handle state B break...}NEW WAY:void run_AI{if (condition A) dostateA()else if (condition B) dostateB()...}void dostateA(){// code to handle state A }void dostateB(){// code to handle state B }
.
.
.
and here's the new AI, ready to cut and paste into the code and translate from pseudocode to real code. this version i named the "B2" api, so
its functions and pre-defined constants begin with "B2". As i wrote it, i split it up based on call hierarchy, just to see how many levels of AI there were. Turns out there are seven levels of AI, with run_AI at the highest level, and calc_amount2turn, turn_unit, and calc_dir2loc at the lowest level (move_unit ended up at the second lowest level).
.------------------------------------------------------------LEVEL 1 (top level) int B2run_AI (13 types of AI, 24 runstates)==================================if avian if do_avian_common_AI, retelse if do_common_AI, retif BM, B2run_BMelse if avian flunkey, B2run_avian_flunkeyelse if flunkey, B2run_flunkeyelse if friendly, B2run_friendlyelse if defloc, B2run_deflocelse if hostile, B2run_hostileelse if thief, B2run_thiefelse if avian_predator, B2run_avian_predatorelse if predator, B2run_predatorelse if avian_defend, B2run_avian_defendelse if defend, B2run_defendelse if avian_maintain_distance, B2run_avian_maintain_distanceelse B2run_maintain_distance -------------------------------------------------------------------------------------LEVEL 2 int B2do_common_AI (returns 1 if called a runstate routine)=========================result=1if cornered, B2attackelse if in collision recovery, B2collision_recoveryelse if halfdead, B2fleeelse if badguy within 20 if badguy stronger, B2flee else B2attackelse if taking fire if have tgt, B2attack else B2flockelse if resting B2standelse result=0ret result int B2do_avian_common_AI (returns 1 if called a runstate routine)=========================result=1if cornered, B2avian_attackelse if in collision recovery, B2avian_collision_recoveryelse if halfdead, B2avian_fleeelse if badguy within 20 if badguy stronger, B2avian_flee else B2avian_attackelse if taking fire if have tgt, B2avain_attack else B2avian_floackelse if resting B2avian_standelse result=0ret result int B2run_BM: (band members)========================if badguys near if in shelter setaction to leave shelter B2doaction else if doing action, stop action if has orders, B2do_orders else B2attackelse if has orders, B2do_orderselse if doing action, B2doactionelse B2stand int B2run_flunkey (pet land animals, warriors, and companions)=========================if far from owner, B2moveto_ownerelse if badguys near if has orders, B2do_orders else B2attackelse if has orders, B2do_orderselse if talking to BM, B2standelse if >20 from owner, B2moveto_ownerelse B2stand int B2run_avian_flunkey (pet avians)=========================if far from owner, B2avian_moveto_ownerelse if badguys near if has orders, B2do_avian_orders else B2avian_attackelse if has orders, B2do_avian_orderselse if talking to BM, B2avian_standelse if >20 from owner, B2avian_moveto_ownerelse B2avian_stand int B2run_friendly (friendly cavemen)========================= if CRH caveman within 500 of home if >50 from home, B2moveto_home else if badguys near home, B2attack else if talking to BM, B2stand else B2grazeelse if badguys near, B2attack else if talking to BM, B2stand else B2graze int B2run_defloc (cavemen or land animals defending a location)==========================================if far from loc, B2moveto_locelse if badguys near, B2attackelse B2stand int B2run_hostile (hostile cavemen)============================if badguys near, B2attackelse B2graze int B2run_thief (thieves)===========================if in approach mode, B2thief_approachelse B2thief_run int B2run_predator (wild land predators)=======================================================if hunting if carcass nearby, B2eatkill else if has tgt, B2hunt else B2flockelse if eating if carcass nearby, B2eatkill else B2flockelse B2flock int B2run_avian_predator (wild avian predators)=======================================================if hunting if carcass nearby, B2avian_eatkill else if has tgt, B2avian_hunt else B2avian_flockelse if eating if carcass nearby, B2avian_eatkill else B2avian_flockelse B2avian_flock int B2run_defend (wild land animals w/ defend AI)==============================if badguys near, B2attackelse B2graze int B2run_avian_defend (wild avians w/ defend AI)==============================if badguys near, B2avian_attackelse B2avian_graze int B2run_maintain_distance (wild land animals)=========================if badguys near, B2fleeelse B2graze int B2run_avian_maintain_distance (wild avians)=========================if badguys near, B2avian_fleeelse B2avian_graze --------------------------------------------------------------------LEVEL 3 int B2do_orders=============================set state based on the unit's orders int B2do_avian_orders=============================set state based on the avian unit's orders int B2graze=======================as current graze, adds migrate.calls: B2stand, B2wander, B2flock, B2migrate int B2avian_graze=======================as current graze, adds migrate.calls: B2avian_stand, B2avian_wander, B2avian_flock, B2avian_migrate ------------------------------------------------------------------------------LEVEL 4low level routines, perform the desired actions: B2doaction=============call doaction_mode B2attack=============B2turn2tgt(closest badguy)if B2is_facing_tgt(closest badguy) run do attack B2hunt============call B2attack B2avian_attack===============if tgt behind and rng<50 climb runelse turn2tgt(closest badguy) set pitch run do attack B2avian_hunt====================call B2avian_attack B2collision_recovery==========================turn2dir(CR direction)if is_facing(CR direction) run inc CR counter B2avian_collision_recovery=============================turn2dir(Collision Recovery direction)climbruninc Collision Recovery counter B2flee===========================turnfromtgt(closest badguy)run B2avian_flee========================turnfromtgt(closest badguy)climbrun B2flock======================turn2tgt(leader)walk B2avian_flock====================turn2tgt(leader)set pitchrun B2stand=================recover fatigue B2avian_stand========================if airborne, landelse recover fatigue B2moveto_owner========================turn2tgt(owner)run B2avian_moveto_owner================================turn2tgt(owner)set pitchrun B2wander========================turn2dir(wander dir)walk B2avian_wander===========================turn2dir(wander dir)set pitchrun B2migrate========================turn2dir(migrate dir)walk B2avian_migrate====================turn2dir(migrate dir)set pitchrun B2moveto_loc=======================turn2loc(loc)run B2eatkill========================turn2tgt(closest carcass)if at carcass, eatelse walk B2avian_eatkill=========================turn2tgt(closest carcass)set pitchif at carcass if airborne, land else eatelse run B2thief_approach=====================turn2tgt(player)runif at tgt, do dialog B2thief_run=======================turnfromtgt(player)run ------------------------------------------------------------------------------------------LEVEL 5 B2turn2tgt(closest badguy, leader, NPC owner, closest carcass, BM owner, or player) ======================================================================calc dir to tgtcall B2turn2dir(dir to tgt) B2turn_from_tgt(closest badguy,player)======================================calc dir to tgtcall B2turn2dir(dir to tgt + 180) B2turn2loc(loc)====================================dir=B2calc_dir2locB2turn2dir(dir) B2is_facing_tgt(closest badguy) returns 1 if unit is facing its tgt=====================================================dir=B2calc_dir2tgtif B2is_facing_dir(dir) ret 1ret 0 B2tgt_is_behind returns 1 if tgt is behind the unit=========================================================dir=B2calc_dir2tgtif B2is_facing_dir(dir+180) ret 1ret 0 if airborne: =================================if unit y > heightmap at unit x,z, ret 1ret 0 if at carcass=====================a=closest_carcassif B2rng2tgt(a)<10 ret 1ret 0 B2climb========================set pitch up B2set_pitch===========================set pitch as required by situation B2run=====================move at sprint/run speedcalc amount to moveB2move_unit(amount) B2walk=====================move at walk speedcalc amount to moveB2move_unit(amount) B2land=================================diverunif alt <=0, alt=0 B2eat===========================if full, hunting=false B2do thief dialog==============================show dialogif get stuff, thief approach mode=0else make thief a hostle B2recover_fatigue (standing)=============================decerase fatiguellim fatigue to 0 B2do_attack================call do_animal_attack B2do_avian_attack=======================call do_avian_attack B2incCRcounter===================counter++if counter >= MAX, in_collision_recovery=false -------------------------------------------------------------------------------------LEVEL 6 B2turn2dir(CR dir,wander dir,migrate dir)====================================================amount=B2calc_amount2turnB2turn_unit(amount) B2is_facing_dir(CR dir) returns 1 if the unit is facing in the indicated direction==============================================================if abs ( dir - unit yr ) <= 30 ret 1ret 0 B2rng2tgt (<50, at tgt) =============================================returns rng to tgt B2calc_dir2tgt===========================loc=tgt loccall B2calc_dir2loc get_closest_badguy=========================definition of "badguy" based on unit type.does best search of band members and/or animals get_owner ============================animal[n].owner, and animal[n].owner_is_caveman get_leader===================================== findfirst, same species (same animal type) get_closest_carcass======================================best search of animals: active, dead, not butchered. get_player_controlled_BM==============================return cm0 calc_amount2move========================================================// speed is based on walk/run/sprintif using missile wpn, desired rng=missile wpn rngelse desired rng=unit rad+tgt radamount=rng2tgt-desired rngif amount > speed, amount = speedif amount < -speed, amount = -speed B2move_unit(amount)======================================new loc=current loc+move amountif no collisions, current loc = new loc ----------------------------------------------------------------------------------------------------LEVEL 7 B2calc_amount2turn=====================================given desired dir, current dir, max turnrate:amount=desired-currentlimit( &amount, -max, max) B2turn_unit(amount)========================================animal[n].yr+=amountwhile (animal[n].yr >= 2*pi) animal[n].yr-=2*piwhile (animal[n].yr < 0) animal[n].yr+=2*pi B2calc_dir2loc(loc)================================atan dz/dx or something like that
.
.
.
once this is implemented, audio and action animations are the only really big things left to do.

0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement
Advertisement