

//***Che this is the base for synth monsters who are not marines
// Creted by cloning my successful mechanics from synth marinnes

ACTOR AbstractSynthMonster
{

	Game Doom
	
	MONSTER
	-FRIENDLY	
	
	MaxStepHeight 24
	MaxDropOffHeight 32	
	
	var int user_sleeping;
	var int user_item_no;
	var int user_serverside_sfchk;	

	var int user_head_tid;
	var int user_head_type;
	var int user_head_rel;
	var int user_head_scale;
	var int user_head_xyzf; /* 
		a packed value: 
		bits 0..7 =x+128, clamped to -128..127
		bits 8..15 =y+128, clamped to -128..127
		bits 16..23 =z, clamped to 1..255
		bit 29 is a command to assume an unique TID, used in monster-on-monster headshotting
		A zero value is a command to terminate
	*/	
	
	var int user_syn_mode;
	var int user_see_after_wp_sw;
	
	+NODROPOFF // can *only* go over the edge if kicked. Too much usage of A_Recoil otherwise.

	var int user_aggro_at_head; // required for the ACS script "FBD_TryReAggroAtHead"
	
	var int user_in_air; 
	var int user_has_los; // used by the weapon phase, updated by the movement phase
	var int user_wp_cooldown; // remaining cooldown tics 
	var int user_notarget_cooldown; 
	var int user_strafe; // strafing speed x100 (absolute value, would match actual speed to this randomly)
	var int user_backpedal; // x100, may be negative for bumrushing or being too far
	var int user_shots; // shots remaining in sequence
	var int user_shot_cooldown; // between shots in a burst
	var int user_charge; // weapon charge (for snipers: their sniping delay)
	
	var int user_anim_frame_time;
	var int user_anim_frame; 

	// controlling variables, are set in the weapon switching state:
	var int user_can_jump; //if 0, will never try jumping
	var int user_makes_footstep_sounds;
	var int user_ambush_chance; // when finishes charging and finds there is no LS. 
		// Is checked at blindfire attempt for the first shot. Not applicable to bfg.
	var int user_ambush_duration; // tics without LOS and not firing before going back to See
	var int user_burst_length;
	var int user_fire_period; // cooldown before the next shot in the burst
	var int user_weapon_cooldown_time;  // in effect after all shots were fired, can't fire again NOR switch weapon until this many tics pass
	var int user_charge_time; // set if weapons requires charging. 
	
	// Ignored while in the air *unless* user_stand_still is set
	// Angle adjustment is disabled while charging (bfg9000, minigun).
	// The rocket launcher also has a very small charging time, to lessen aiming into walls
	var int user_stand_still; // Stop moving when charging -- also disables shooting in air. For BFG.
	var int user_melee_range;
	var int user_too_close_range; // if closer and facing the target, will switch to the synth attack state
		// regardless of target's visibility and begin backpedaling/circle-strafing
	var int user_enemy_memory;
	
	var int user_muzzle_z; // controls the firing point
	
	// *actual* velocities calculated from delta x/y between tics 
	//   (momx/momy cannot be relied upon to check if actor is stuck 
	//    trying to push through a wall via ThingThrust)
	var int user_rightward_vel; // lateral (rightward) velocity *100
	var int user_forward_vel;	// dilatational (forward) *actual* velocity *100

	var int user_head_tic; // descendants may use this to decrease headbox adjust frequency
	var int user_sfx_tic; // used by various weapon animations
	
	var int user_awakened; // had a target at least once. 
		// Without this, Idle jumps to Stand instead of wandering.
		// Used to invoke WeaponSwitch after Spawn	
		
	var int user_weapon; // set to this before jumping to WeaponSwitch 
		// to switch to a weapon other than default (e.g. melee)
		// The caller is responsible for making sure the weapon is not in the process of charging or firing.
		// 31 - Uberzoldat, Gewehr 98 sniper rifle
		// 32 - Uberzoldat, MG-42
		// 33 - Fritz Scorzeny, the EDAY42 boss with four MG-42s
		// 34 - regular nazi
		
	var int user_default_weapon; // used if user_weapon is zero. 
		// All descendants rely on this exclusively
		//  to swap between melee and ranged!
	var int user_melee_weapon;		
	
	var int user_jump_power; // spawn sets this to 50, then calls an ACS script that reduces it to 37 for EDAY mars maps
	// to be passed to thrust thing z in Jump
	
	var int user_thr_acc; // current threat assessment, 0 to 256
	var int user_thr_cooldown; // to make it run every 6 tics, not every tic
	
	var int user_thr_mul; // target's danger level, 1 and up
	
	var int user_thr_hrr; // target's Horrible Rape Radius, in parallel to user_too_close_range
	var int user_thr_chaaarge; // boolean, rush the target to close in quickly (say, we have chainsaw while he has rocket launcher)	
	
	var int user_prev_x; // unfortunately, momx & momy *cannot* be relied upon, 
		// these do not zero out on collision and cannot represent actual speed
	var int user_prev_y;
	var int user_dx;
	var int user_dy;
	
	var int user_ambush; // boolean	
	
	var int user_strafing_angle; // to use A_Wander in a sideways direction for strafing
	var int user_swander_cd; // to regulate A_Wander-based strafing, this slows it down to once in N tics
	var int user_stuck_det; // accumulates while not movilg while trying to. Until it decays back to zero, use A_Wander based strafing.
	var int user_move_wander; // only 0 or 1 allowed, otherwise multiplayer sync scripts fail!
		// movement method: using A_Wander to move, otherwise ThrustThing	
	var int user_loiter_count; // to timeout syn modes 2. 3 and 4 after 90 tics.
	
	var int user_nag_period; // if zero, mechanism disabled
	var int user_nag_cooldown; // after nagging, will set it to Random(user_nag_period / 2, user_nag_period)
	
	var int user_prev_wpn; // used by weapon switching to avoid making a sound when switching to the same weapon
	
	var int user_thr_min; // floor for user_thr_acc	
	
	var int user_npc_tgt_x; // coordinates where last seen target
	var int user_npc_tgt_y;
	var int user_npc_tgt_valid;	
	
	var int user_speed_limit;	
	
	// used by the bunch of probes that adjust blindfire direction
	var int user_best_d;
	var int user_best_a;
	var int user_best_p; // is considered invalid if user_best_d is zero - e.g. use autoaimed pitch instead
	var int user_best_cd; // to fire every 4 tics while charging the weapon, continuing adjusting
	
	var int user_probed_angle;
	var int user_wander;
	var int user_angle;
	
	var int user_footstep_mask; // a bit mask on which animation frames visit the AnimFootstep state (its duration must be zero)
		// 1 -> frame 1, 2 - frame 2, 4 - frame 3, 8 - frame 4
	
	PainChance "Ice", 48

	States 
	{
		Jump:
			"----" A 0 A_TakeInventory("evmarinecanjump", 1)
			
			// Encountered  a curious bug: they kept jumping mid-air 
			// until they reached stratosphere then splattered on landing
			"----" A 0 A_JumpIf(!user_can_jump || (user_syn_mode && (user_in_air || z - floorz > 32)), "SynthContinue")
			
			Goto SynthJump // takes care of jumping and landing -- in parallel to shooting. 
				// Can start shooting if acquires target LOS while in jump	
		
		Triumph:
			"----" A 1 // ancestors must redefine this for something prominent
			Goto Idle
			
		CustomKinslayerCheck:
			"----" A 0
			Goto MissileAfterDodgeRoll	
			
		MeleeAttack:
			"----" A 0
			Goto See
			
		BattleCry:
			"----" A 0 //A_PlaySound("demon/sight", CHAN_VOICE)
			Goto AfterBattleCry
			
		Nag: 
			"----" A 0 //A_PlaySound("demon/active", CHAN_VOICE)
			Goto NagDone	
			
		CheckForFatality:  // melee attacks must jump here afterwards,
			// *without* invoking any A_Look or A_Chase 
			//    that would jump to Idle as inevitably as death and taxes!
			
			// insert your fatality checks here when overriding this state!
			
			"----" A 0 A_JumpIf(user_see_after_wp_sw == 2, "IdleLoop")
			"----" A 0 A_JumpIf(user_syn_mode, "ThreatSensePhase")
			"----" A 4 A_JumpIf(true, "See")
			Wait			
			
			
		KilledMyTarget:
			"----" A 0 A_JumpIfInTargetInventory("PlayerIsDead", 1, "Triumph")
			"----" A 0
			Goto Idle				
	
		Pain.Ice:
			"----" A 10 A_Pain
		Pain:
		SynthPain:
			"----" A 0
			//"----" A 0 A_SetUserVar("user_aggro_cooldown", 0)
			"----" A 0 A_SetUserVar("user_strafe", user_strafe < 10 ? 10 : user_strafe)

			Goto PainActually
			
		PainActually:
			"----" A 0 A_JumpIf(true, "Pain_MonsterDefined")
/*			
			"----" A 0 A_JumpIf(user_weapon == 31, "Pain_UberSniper")
			"----" A 0 A_JumpIf(user_weapon == 32, "Pain_UberZoldat")
			"----" A 0 A_JumpIf(user_weapon == 33, "Pain_Scorzeny")
			"----" A 0 A_JumpIf(user_weapon == 34, "Pain_SSNazi")
*/			
			"----" A 3 A_Pain // error state, no pain defined
			Goto PainContinue
			
		PainContinue: // weapon-specific pain animations (see descendant classes) return here
			"----" A 3
			"----" A 0 A_JumpIf(user_syn_mode != 1 && user_in_air || z - floorz > 32, "SynthContinue")
			Goto ShuffleFromPain
			
		Pain.Avoid:
		Pain.RailAvoid: // only works on those subscribed - e.g. Scorzeny
		Pain.FireInTheHole:
		Pain.HurrDurrMeHazGrenaed:
		
			"----" A 0
			//"----" A 0 A_SetUserVar("user_aggro_cooldown", 0)
			"----" A 0 HealThing(1)
			"----" A 0 A_SetUserVar("user_thr_acc", user_thr_acc < 155 ? user_thr_acc + 100 : 255) // threat assessment increase
		
			// just circle-strafe really fast. Do NOT interrupt bfg charging.
			"----" A 0 A_JumpIf(user_syn_mode == 1 && (user_charge && user_stand_still), "ShuffleFromPain")
			
			"----" A 1 A_Jump(256, "Jump")
			Wait
			
		See:
			"----" A 0 A_ChangeFlag("NODROPOFF", 1) // just in case: some clear it in their Pain.Kick
			Goto SynthSee
			// you may still use a normal See state, just check periodically for 
			// "----" A 0 A_JumpIfTargetInLOS("SynthBackpedal", 0, JLOSF_DEADNOJUMP | JLOSF_NOSIGHT, user_thr_hrr > user_too_close_range ? user_thr_hrr : user_too_close_range)
		
		SynthSee:
			// The See state is another quasi-synthetic state!
			"----" A 0
			"----" A 0 A_JumpIf(!user_syn_mode, 3)
			"----" A 0 A_SetUserVar("user_syn_mode", 0)
			"----" A 0 ACS_NamedExecuteAlways("SkulltagTransmitSynStateToClient") // the Zandronum game engine does never sync user variables nor monsters' inventories
			
			"----" A 0 A_JumpIf(user_awakened, 2)
			"----" A 0 A_SetUserVar("user_awakened", 1)
			"----" A 0 A_ChangeFlag("NODROPOFF", 1)
			
			// just in case some weird shit happens
			"----" A 0 A_CheckFlag("SHOOTABLE", 3, AAPTR_DEFAULT) // do not set if already shootable
			"----" A 0 A_ChangeFlag("SHOOTABLE", 1)
			"----" A 0 A_ChangeFlag("INVULNERABLE", 0)
			
			// slaughtermap manage - warming the headbox up
			"----" A 0 A_JumpIf(!user_sleeping, 4) // forgo the expensive sight check if already awake
			"----" A 0 A_JumpIfInTargetInventory("IsPlayer", 1, 2) // bypass the sight check 
			"----" A 0 A_CheckSight(2) // out of sight of any player, AND attacking another monster, keep slumbering
			"----" A 0 A_SetUserVar("user_sleeping", 0)				

			"----" A 0 A_JumpIfInTargetInventory("PlayerIsDead", 1, "Triumph")
			
			Goto ChasePlayer
			
		ChasePlayer:
		
			// slaughtermap manage
			"----" A 0 A_JumpIf(!user_sleeping, 3) // forgo the expensive sight check if already awake
			"----" A 0 A_CheckSight(2) // do not consider ourselves awake if none of the players can see us
			"----" A 0 A_SetUserVar("user_sleeping", 0)
			"----" A 0 A_JumpIf(user_serverside_sfchk != -1, 3) // -1 means ACS commands us to do the radiusgive
			"----" A 0 A_RadiusGive("SfestCounterServerside", 500, RGF_MONSTERS | RGF_CUBE | RGF_NOSIGHT, 1)			
			"----" A 0 A_SetUserVar("user_serverside_sfchk", 1) // reply that we did the deed	
			
			"----" A 0 A_ChangeFlag("NOPAIN", 0)
			"----" A 0 A_SetUserVar("user_anim_frame", 0)
			"----" A 0 A_SetUserVar("user_anim_frame_time", 0)
			
			// Switch to the synth state to begin backpedaling -- *without* line of sight.
			//  Results in evil marines ambushing player at proper distances for each specific weapon.
			//  Also prevents NPC marines from walking too close to monster around a doorframe edge.
			
			// All hail A_Warp and A_JumpIfTargetInLOS, the indispensable tools of incredible might!
			
			//P.S. Also results in both evil and npc marines staying da fug out of the bosses' Horrible Rape Radius.
			// If you fight a helicopter or a super cyberdemon, your npcs will keep huddling in cover.
			//  note user_thr_chaaarge does not affect this, charging is made as a part of the missile state
			
			// without sight it is the same as A_jumpifcloser EXCEPT it won't jump if target is dead
			"----" A 0 A_JumpIfTargetInLOS("SynthBackpedal", 0, JLOSF_DEADNOJUMP | JLOSF_NOSIGHT, user_thr_hrr > user_too_close_range ? user_thr_hrr : user_too_close_range)
			"----" A 0 // an empty frame to jump to
			
			
			Goto ChaseLoop
			
			//***Che this code here is weird because I emulate the original jump checking code
			//  to the best of my ability.
			// It was quirky but worked *extremely* well after I tweaked it fixing a couple minor issues.
			// As usual for Mark-sensei: a genius solution abandoned on the cusp of working properly :(			
			
		ChaseLoop:
			// manage weapon cooldown
			"----" A 0 A_SetUserVar("user_wp_cooldown", (user_wp_cooldown < 2 ? 0 : user_wp_cooldown - 2))
			Goto ChaseLoopMovement	

		ChaseLoopMovement:
			"----" A 0 A_JumpIf (user_anim_frame_time > 0, "ChaseLoopMoveSkipRecoil")
			"----" A 0 A_Recoil(-2) // once per 4 tics while ChaseLoop loops every 2 tics
		ChaseLoopMoveSkipRecoil:	
			//"----" A 0 A_JumpIf(user_aggro_cooldown, "ChaseLoopWanderInstead")
			
			"----" A 0 A_JumpIf(user_anim_frame == 2, "ChaseFrame2") // all return to ChaseLoopContinue
			"----" A 0 A_JumpIf(user_anim_frame == 3, "ChaseFrame3")
			"----" A 0 A_JumpIf(user_anim_frame == 4, "ChaseFrame4")
			"----" A 1 A_JumpIf(true, "ChaseFrame1")
			Wait
			
		ChaseLoopContinue:
		
			"----" A 0 A_JumpIf(user_wp_cooldown, 3) // do *not* initiate going into the Missile syn mode 1 until weapon cooldown is over!			
			"----" A 0 A_SetUserVar("user_angle", angle * 100.0) // CHF_DONTMOVE fucks the angle up
			"----" AA 0 A_Chase("Missile", "Missile", CHF_DONTMOVE) // a (double) chance to jump to the Missile state as per normal monster behavior
			"----" A 0 A_SetAngle("user_angle", angle * 0.01)
			"----" A 0 A_JumpIf(!user_anim_frame_time && user_anim_frame == 0, "ChaseFireJumpCheck")
			"----" A 0 A_JumpIf(user_can_jump && !user_anim_frame_time && user_anim_frame == 1, "ChaseCheckJump")
		ChaseLoopContinue2:
			"----" A 0 A_SetUserVar("user_anim_frame_time", user_anim_frame_time + 1) //((momx * momx) + (momy * momy) < 20 ? 1 : 2))
			"----" A 0 A_JumpIf(user_anim_frame_time >= 2, 1)
			Goto ChaseLoop
			"----" A 0 A_SetUserVar("user_anim_frame_time", 0)
			"----" A 0 A_SetUserVar("user_anim_frame", user_anim_frame + 1)
			
			//"----" A 0 A_JumpIf(!user_makes_footstep_sounds || (user_anim_frame != 2 && user_anim_frame != 4), 2)
			"----" A 0 A_JumpIf(!(user_footstep_mask & (1 << user_anim_frame)), 2)
			"----" A 0 A_SpawnItemEx("FootStep6", 0, 0, 8, 0, 0, 0, 0, SXF_SETMASTER )
			
			"----" A 0 A_JumpIf(user_anim_frame < 4, "ChaseLoop")
			
			"----" A 0 A_SetUserVar("user_nag_cooldown", user_nag_cooldown > 16 ? user_nag_cooldown - 16 : 0)
			"----" A 0 A_JumpIf(!user_nag_cooldown, "Nag") // must return to NagDone

			Goto ChasePlayer
			
		NagDone:
			"----" A 0 A_SetUserVar("user_nag_cooldown", Random(user_nag_period / 2, user_nag_period))
			Goto ChasePlayer			
			
		ChaseFireJumpCheck:
			"----" A 0 A_JumpIf(z - floorz > 16, "ChaseJumpCancel")
			"----" A 0 A_JumpIfInTargetLOS(4, 180, 0, 100) // a certain fix for close distances
			"----" A 0  A_SetUserVar("user_probed_angle", angle) // so that probes are invalidated if we turn around in those 4 tics
				// P.S. Also if no LOS forces facing in this direction while in jump!
			"----" A 0 A_CustomMissile("EvilMarineCheckFront", 32, 0, 0, 2, 0)
			"----" A 0 A_CustomMissile("EvilMarineCheckJump", 64, 0, 0, CMF_AIMDIRECTION, 35)
			Goto ChaseLoopFinish
			
		ChaseCheckJump:
			"----" A 0 A_JumpIfInventory("evmarinenoway", 1, "ChaseJumpCheck2")
			"----" A 0 A_JumpIf(CallAcs("GetZDeltaToTarget") > 40, "ChaseJumpCheck2")
			Goto ChaseLoopFinish
			
		ChaseJumpCheck2:
			"----" A 0 A_JumpIf(z - floorz > 16, "ChaseJumpCancel")
			"----" A 0 A_FaceTarget
			"----" A 0 A_TakeInventory("evmarinenoway", 1)
			"----" A 0 A_JumpIf(CallACS("GetAngleDelta360iAbs", angle, user_probed_angle) > 50, "ChaseLoopFinish") 
			"----" A 0 A_JumpIfInventory("evmarinecanjump", 1, "Jump")
			Goto ChaseLoopFinish
			
		ChaseJumpCancel:
			"----" A 0 A_TakeInventory("evmarinenoway", 1)
			"----" A 0 A_TakeInventory("evmarinecanjump", 1)
			Goto ChaseLoopFinish
			
		ChaseLoopFinish:
			"----" A 0 A_JumpIf(user_wp_cooldown, "ChaseLoopContinue2")
			"----" A 0 A_SetUserVar("user_angle", angle * 100.0) // CHF_DONTMOVE fucks the angle up
			"----" AA 0 A_Chase("Missile", "Missile", CHF_DONTMOVE) // attack visible targets
			"----" A 0 A_SetAngle("user_angle", angle * 0.01)
			Goto ChaseLoopContinue2	


		Idle:
		SynthIdle:
			"----" A 0 A_CheckFlag("SHOOTABLE", 3, AAPTR_DEFAULT) // do not set if already shootable
			"----" A 0 A_ChangeFlag("SHOOTABLE", 1)
			"----" A 0 A_ChangeFlag("INVULNERABLE", 0)
			
			"----" A 0 A_SetUserVar("user_syn_mode", 0)
			
			"----" A 1 // crash guard protection frame against infinite zero-time loops
			
			// clear the target knowledge -- but not the threat accumulator!
			"----" A 0 A_SetUserVar("user_thr_chaaarge", 0)
			"----" A 0 A_SetUserVar("user_thr_mul", 0)
			"----" A 0 A_SetUserVar("user_thr_hrr", 0)
			
			"----" A 0 A_SetUserVar("user_wander", Random(1, 3))
			
			// switch to ranged weapon if we have one
			// also clears a shitton of variables
			"----" A 0 A_JumpIf(user_sleeping, "IdleLoop") // non-conventional use of this variable, to prevent weapon switching repeatedly (which makes sound)
			"----" A 0 A_SetUserVar("user_see_after_wp_sw", 2) // go to idle loop afterwards
			"----" A 0 A_SetUserVar("user_weapon", user_default_weapon)
			Goto WeaponSwitch
			
		IdleLoop:	
			"----" A 4 // non-zero duration -- just in case
			
			// A hack: let weapon cooldown stay undecayed on idle. This gives a random emergent 
			//   extra pre-fire delay to the first shot after acquiring a target
			
			"----" A 0 A_Look

			"----" A 0 A_JumpIf(user_wander > 0, "WanderCycle")
			
			"----" A 0 A_SetUserVar("user_sleeping", 0)	// headbox slaughtermap optimization
			"----" A 0 A_Jump(16, "RandomWander")
			Loop
		
		RandomWander:
			"----" A 0 A_SetUserVar("user_wander", Random(3, 9))
			Goto IdleLoop
		
		Missile:
			"----" A 0
			Goto SynthMissile
			// you can still use a normal missile state, only switching to synth state in specific circumstances
			
		SynthMissile:
			// slaughtermap manage - warming the headbox up
			"----" A 0 A_JumpIf(!user_sleeping, 4) // forgo the expensive sight check if already awake
			"----" A 0 A_JumpIfInTargetInventory("IsPlayer", 1, 2) // bypass the sight check 
			"----" A 0 A_CheckSight(2) // out of sight of any player, AND attacking another monster, keep slumbering
			"----" A 0 A_SetUserVar("user_sleeping", 0)

			"----" A 0 A_JumpIf(user_wp_cooldown, "See")
			
			"----" A 0 A_Recoil(-4)
			"----" A 0 A_FaceTarget
		
		
			// weapon cooldown is always retained 
			"----" A 0 A_SetUserVar("user_wp_cooldown", user_wp_cooldown > 2 ? user_wp_cooldown - 2 :  0)

			"----" A 0 A_SetUserVar("user_anim_frame", 0)	
			"----" A 0 A_SetUserVar("user_anim_frame_time", 0)
			
			"----" A 1 A_JumpIf(true, "CustomKinslayerCheck") // must jump to MissileAfterDodgeRoll

	
		MissileAfterDodgeRoll:	
		
			"----" A 0 A_SetUserVar("user_syn_mode", 1) // just in case
			"----" A 0 A_SetUserVar("user_notarget_cooldown", 0)
			
			"----" A 0 ACS_NamedExecuteAlways("SkulltagTransmitSynStateToClient") // the Zandronum game engine does never sync user variables nor monsters' inventories
			"----" A 0 A_SetUserVar("user_shots", user_burst_length) // to vary burst length, add more during firing
			"----" A 0 A_SetUserVar("user_ambush", 0)
			"----" A 0 A_SetUserVar("user_shot_cooldown", 0)
			"----" A 0 A_SetUserVar("user_loiter_count", 0)
			"----" A 0 A_SetUserVar("user_strafe", user_strafe < 5 ? 5 : user_strafe)
			"----" A 0 A_SetUserVar("user_backpedal", 0)
			
			"----" A 0 A_SetUserVar("user_charge", 0)
		
			"----" A 0 A_TakeInventory("MeleeMiss", 3)
			
			// Always assuming we have LOS on entering the missile state -- and *always* calling A_FaceTarget.
			// If there is no actually LOS or the target is invisible, will register losing LOS in the Move phase.
			"----" A 0 A_SetUserVar("user_has_los", 1)
			"----" A 0 A_FaceTarget
			"----" A 0 A_SetUserVar("user_best_a", angle * 182.0444)

			"----" A 0 A_SetUserVar("user_prev_x", x)
			"----" A 0 A_SetUserVar("user_prev_y", y)
			"----" A 1 // wait one tic to make actual velocities accumulate into delta x, y
			
			Goto SynthLoop
			
		//***Che SynthLoop is a synthetic attack state
		// made of four semi-independent layers:
		// MovePhase -> AnimPhase -> WeaponPhase -> ThreatSensePhase -> to the beginning	
		
		// where move and weapon phases have zero duration
		// and the anim phase always takes 1 tic
		// (basically it's a poor man's multithreading)
		
		ShuffleFromPain: //<- The custom pain state must redirect here if weapon is charging
			// Circle-strafe sharply instead of dodge-rolling
			"----" A 0 A_SetUserVar("user_strafe", user_strafe > 10 ? user_strafe : 10)
			"----" A 0 A_JumpIf(user_syn_mode, "SynthContinue")
			Goto SynthBackpedal
		
		SynthContinue: // return from pain state and so on
			"----" A 0 // retain previous syn mode
			"----" A 0 A_JumpIf(!user_syn_mode, "SynthBackpedal")
			Goto WeaponPhase
			
		SynthBackpedal:
			"----" A 0 A_SetUserVar("user_syn_mode", 2)
			"----" A 0 A_SetUserVar("user_loiter_count", 0)
			"----" A 0 A_FaceTarget
			"----" A 0 A_SetUserVar("user_angle", angle * 100.0)
			"----" A 0 A_SetUserVar("user_strafe", user_strafe > 3 ? user_strafe : 3)
			"----" A 0 ACS_NamedExecuteAlways("SkulltagTransmitSynStateToClient") // the Zandronum game engine does never sync user variables nor monsters' inventories
			Goto MovePhase
			
		SynthJump:
			"----" A 0 A_JumpIf(!user_can_jump, "SynthBackpedal")
			"----" A 0 A_SetUserVar("user_syn_mode", 4)
			"----" A 0 A_SetUserVar("user_loiter_count", 0)
			"----" A 0 ACS_NamedExecuteAlways("SkulltagTransmitSynStateToClient") // the Zandronum game engine does never sync user variables nor monsters' inventories
			"----" A 0 A_SetUserVar("user_in_air", 1)
			Goto MovePhase
			
		ExitSynthLoop:
			"----" A 0 A_SetUserVar("user_notarget_cooldown", 0)
			"----" A 0 A_SetUserVar("user_syn_mode", 0)
			"----" A 0 ACS_NamedExecuteAlways("SkulltagTransmitSynStateToClient")
			
			"----" A 0 A_SetUserVar("user_see_after_wp_sw", 1) // go to see afterwards
			
			"----" A 0 A_JumpIf(user_weapon == user_default_weapon, "See")
			"----" A 0 A_SetUserVar("user_weapon", user_default_weapon) // switch to ranged
			
			Goto WeaponSwitch			
			
		SynthLoop: // NEVER jump here directly, use entry points!
			// using "----" (retain previous) to respect the quirks of the Zandronum multiplayer client
			// -- we may return here from pain, which is unique per descendant class
			
			"----" A 0 A_SetUserVar("user_nag_cooldown", user_nag_cooldown > 1 ? user_nag_cooldown - 1 : 0)
			
		MovePhase: 
		
			// in all modes except 1 (missile) and 3 (jump), forced face target every tic!
			"----" A 0 A_JumpIf(user_syn_mode == 1 || user_syn_mode == 3, 2)
			"----" A 0 A_FaceTarget
		
			// they get rounded down to integers in the process
			"----" A 0 A_SetUserVar("user_dx", x - user_prev_x < -64 || x - user_prev_x > 64 ? 0 : x - user_prev_x)
			"----" A 0 A_SetUserVar("user_dy", y - user_prev_y < -64 || y - user_prev_y > 64 ? 0 : y - user_prev_y)

			"----" A 0 A_SetUserVar("user_prev_x", x)
			"----" A 0 A_SetUserVar("user_prev_y", y)
			// map: x east, y north, 0 angle east, 90 angle north
			// actor: x forward, y rightward 
			// -- note in this system y is *flipped* compared to the map's system!
			//    where y, momy use map's
			//    and SpawnItemEx's y, yvel use actor's, relative to the actor
			//    Quoting a comment from Zandronum's source code implementing A_SpawnItemEx
			//    (thingdef_codeptr.cpp, line 2604):
			//        in relative mode negative y values mean 'left' and positive ones mean 'right'
			//        This is the inverse orientation of the absolute mode!
			//        ...
			//        x = self->x + FixedMul(xofs, finecosine[ang]) + FixedMul(yofs, finesine[ang]);
			//        y = self->y + FixedMul(xofs, finesine[ang]) - FixedMul(yofs, finecosine[ang]);
			
			// here user_dx and user_dy are in the map system where user_rightward_vel is in the actor system
			"----" A 0 A_SetUserVar("user_rightward_vel", !user_dx && !user_dy ? 0 : 100 * ( user_dx * sin(angle) - user_dy * cos(angle)))
			"----" A 0 A_SetUserVar("user_forward_vel", !user_dx && !user_dy ? 0 : 100 * (user_dx * cos(angle) + user_dy * sin(angle)))
			
			
			"----" A 0 A_JumpIf(user_syn_mode == 1 && ((user_charge && user_shots) || user_ambush), 2)
			// In syn mode 1 (missile), loiter count is used for a mode exit cooldown,
			//   cannot switch out until at least 5 tics are spent in it
			"----" A 0 A_SetUserVar("user_loiter_count", user_loiter_count + 1)
		
			// За такое хочется убивать. Себя.
			// Left here as a burning shame of an example HOW NOT TO DO it.
			//"----" A 0 A_JumpIf(!user_charge && user_shots <= 0 && user_notarget_cooldown > user_ambush_duration && !user_in_air, "See") // before los check: some states set this var manually
			
			// Line of sight is cached in a variable to avoid spamming it (the threat evaluation phase 
			//   calls it on its own anyway, but it is throttled by doing the evaluation once in 5 tics)
			"----" A 0 A_JumpIf(CallAcs("FBD_TargetIsInvisible"), "MoveNoLOS")
			"----" A 0 A_JumpIfTargetInLOS("MoveHasLOS", 130, JLOSF_DEADNOJUMP)
			Goto MoveNoLOS
		
		MoveNoLOS:
			"----" A 0 A_SetAngle(user_best_a * 0.005493164) // face the best angle
			"----" A 0 A_JumpIf(user_has_los, "MoveLostLOS")
			Goto MoveMove
		
		MoveHasLOS:	
			"----" A 0 A_FaceTarget
			"----" A 0 A_JumpIf(user_syn_mode == 1, 2) // in the Missile mode, user_best_a 
				// is subject to repeated corrections using probes
				// - so direct angle to target may not be the best firing angle
				//  (probes resolve corners and stuff)
			"----" A 0 A_SetUserVar("user_best_a", angle * 182.0444) 
			"----" A 0 A_JumpIf(!user_has_los, "MoveRegainedLOS")
			Goto MoveMove
			
		MoveRegainedLOS:
			"----"  A 0 A_SetUserVar("user_has_los", 1)
			Goto MoveMove
			
		MoveLostLOS:
			"----" A 0 A_SetUserVar("user_has_los", 0)
			"----" A 0 A_JumpIf(user_syn_mode == 1 && !user_in_air && user_stand_still && (user_ambush || user_charge < user_charge_time || user_shots >= user_burst_length), "MoveLostLOSWhileCharging")
			Goto MoveMove

		MoveLostLOSWhileCharging:
			// currently, you only get here while charging your bfg
			"----" A 0 A_SetUserVar("user_strafe", user_strafe / 2) // cut strafing speed in half
			"----" A 0 A_Stop
			
			// now reverse direction by force-switching to wander mode:
			// a partial clone of MoveSwitchToWander
			"----" A 0 A_SetUserVar("user_swander_cd", 0)
			"----" A 0 A_SetUserVar("user_move_wander", 1)
			"----" A 0 A_SetUserVar("user_angle", angle * 100.0)
			
			// now reverse our lateral movement
			
			"----" A 0 A_JumpIf(user_rightward_vel > 300, "MoveSTWLeft") 
			"----" A 0 A_JumpIf(user_rightward_vel < -300, "MoveSTWRight") 
			"----" A 1 A_Jump(256, "MoveSTWLeft", "MoveSTWRight")
			Wait

		MoveMove:
			// Note: in my previous implementation I was using circle-strafing checks
			//   in this move phase. 
			// Unneeded.
			// Because random strafing generates enough emergent behavior 
			//   to give reliable and lifelike surprising around corners.
		
			"----" A 0 A_JumpIf(user_in_air, "MoveInAir") // jumping allows no other movement
			
			// max (abs(user_backpedal), user_strafe) implemented using trinary operators
			// because OF COURSE Zandronum doesn't know such functions
			"----" A 0 A_SetUserVar("user_swander_cd", user_swander_cd + (user_backpedal > 0 ? (user_backpedal > user_strafe ? user_backpedal : user_strafe) : (- user_backpedal > user_strafe ? - user_backpedal : user_strafe)))			
			
			"----" A 0 A_JumpIf(user_move_wander, "MoveWander")
			Goto MoveThrust
		
		MoveInAir:
			"----" A 0 A_SetUserVar("user_in_air", user_in_air + 1) // the Jump state sets to 1, we begin at 2!
			"----" A 0 A_JumpIf(user_has_los || angle == user_probed_angle, 2)
			"----" A 0 A_SetAngle(user_probed_angle) // cancel any turning aroud we may have made since the probe was fired
			"----" A 0 A_JumpIf(user_in_air == 2, "MoveInAirActuallyJump")
			// !user_syn_mode == 1 because if we are firing it means we had performed A_FaceTarget 
			//   and should continue on our trajectory. No sudden turns in air.
			"----" A 0 A_JumpIf(user_in_air >= 3 && user_forward_vel < 1000 && !user_syn_mode == 1, "MoveInAirJumpAccel") // after one tic spent in jump (moving upwards), accelerate forward
			"----" A 0 A_CheckFloor("MoveLand")
			//"----" A 0 A_JumpIf(user_in_air > 8 && user_in_air < 17 && z - floorz >= 64, "MoveTryWarpForward")
			"----" A 0 A_JumpIf(user_in_air > 60 && momz == 0, "MoveLand") // assume we landed on someone's head
			Goto MoveFinish
	
			
		MoveInAirActuallyJump:	
			"----" A 0 A_TakeInventory("evmarinecanjump", 1)
			"----" A 0 ThrustThingZ(0, user_jump_power ? user_jump_power : 50, 0, 1)
				//***Che: adjust aim *early* if target is invisible
				"----" A 0 A_JumpIf(CallAcs("FBD_TargetIsInvisible"), 2)
				"----" A 0 A_JumpIfTargetInLOS(2)
				"----" A 0 A_FaceTarget
				"----" A 0 // obligatory empty frame to jump to
			Goto MoveFinish
			
		MoveInAirJumpAccel:
			"----" A 0 A_Recoil(-3) //-6)
			"----" A 0 A_CheckFloor("MoveLand")
			Goto MoveFinish			
			
		MoveLand:
			"----" A 0 A_SetUserVar("user_in_air", 0)
			
			//P.S. Frak, they were driving themselves into walls and getting stuck
			//"----" A 0 A_Warp(AAPTR_DEFAULT, 10, 0, 0) // to hopefully push us away from the edge 
				// of the ledge we just jumped onto. Ignore failures.

			// let's try recoil instead... :(		
			"----" A 0 A_Recoil(-10)	
				
			"----" A 0 A_SpawnItemEx("FootStepStrong", 0, 0, 8, 0, 0)
			"----" A 0 A_JumpIf(user_syn_mode == 1, "MoveFinish") // continue our firing sequance
			Goto ExitSynthLoop // we are done here

		MoveThrust:	
			// the old movement mode using ThingThrust. Can get stuck on walls
			
			// in this mode user_swander_cd is used to determine if we want moving at all
			// (see MoveThrustFinish ) and is cleared each tic afterwards
			
			"----" A 0 A_JumpIf(user_strafe < 1, "MoveThrustBackOrForth") // no we do NOT wantt o move
			
			Goto MoveThrustBackOrForth			

		MoveThrustSideways:
			
			// a hack to make them observe the speed limitation!
			"----" A 0 A_JumpIf(user_rightward_vel > (user_speed_limit * 90) || user_rightward_vel < (user_speed_limit * -90),"MoveThrustCoast") //***Che heck no, wander is *glitchy*, actor angle flickers all over the place -- I was unable to get it right! "MoveSwitchToWander")			
			
			// if moving faster than 3 map units per tic, keep moving in that direction
			"----" A 0 A_JumpIf(user_rightward_vel > 300, "MoveThrustRight") // corresponds to 3 map units per tic
			"----" A 0 A_JumpIf(user_rightward_vel < -300, "MoveThrustLeft")
			
			// if speed is low, move randomly (would get unstuck unless in a corner)
			"----" A 1 A_Jump(256, "MoveThrustRight", "MoveThrustLeft")
			Wait // Zandronum client freezes and waits for an update from the server
			
		MoveThrustCoast:	
			 // decay the controlling value over time
			"----" A 0 A_SetUserVar("user_strafe", user_strafe > 0 ? user_strafe - 1 : 0)
			Goto MoveThrustBackOrForth
			
		MoveThrustLeft:
			 // decay the controlling value over time
			"----" A 0 A_SetUserVar("user_strafe", user_strafe > 0 ? user_strafe - 1 : 0)
			"----" A 0 A_JumpIf(user_rightward_vel < -100 * user_strafe, "MoveThrustBackOrForth")//***Che !!!This was fouled up because it was jumping *into* the next state!!!!, 2)
			"----" A 0 ThrustThing((angle*256/360)+64, 2, 0, 0)
			Goto MoveThrustBackOrForth			
			
		MoveThrustRight:
			 // decay the controlling value over time
			"----" A 0 A_SetUserVar("user_strafe", user_strafe > 0 ? user_strafe - 1 : 0)
			"----" A 0 A_JumpIf(user_rightward_vel > 100 * user_strafe, "MoveThrustBackOrForth")//, 2)
			"----" A 0 ThrustThing((angle*256/360)+192, 2, 0, 0)
			Goto MoveThrustBackOrForth
					
			
		MoveThrustBackOrForth:
			"----" A 0 A_JumpIf(user_backpedal > 1 && user_forward_vel > -100 * user_backpedal, "MoveThrustBackpedal")
			"----" A 0 A_JumpIf(user_backpedal < -1 && user_forward_vel < -100 * user_backpedal, "MoveThrustBumrush")
			Goto MoveThrustFinish
			
		MoveThrustBackpedal:
			"----" A 0 A_SetUserVar("user_backpedal", user_backpedal - 1)
			"----" A 0 ThrustThing(angle*256/360+128, 2, 0, 0)
			Goto MoveThrustFinish
		
		MoveThrustBumrush:
			"----" A 0 A_SetUserVar("user_backpedal", user_backpedal + 1)
			"----" A 0 ThrustThing(angle*256/360+128, -2, 0, 0)	
			Goto MoveThrustFinish
			
		MoveThrustFinish:
			// if all velocities are less than half of the largest desired velocity, count that as being stuck in a corner
			
			// note: user_swander_cd is 1x while user_rightward_vel, user_forward_vel are 100x
			
			"----" A 0 A_JumpIf(user_swander_cd > 1 && user_rightward_vel / 100 > - user_swander_cd / 2 && user_rightward_vel / 100 < user_swander_cd / 2 && user_forward_vel / 100 > - user_swander_cd / 2 && user_forward_vel / 100 < user_swander_cd / 2, "MoveThrustStuck")
			
			"----" A 0 A_SetUserVar("user_swander_cd", 0)
			Goto MoveAdjustSpeeds
			
		MoveThrustStuck:
			"----" A 0 A_SetUserVar("user_stuck_det", user_stuck_det + 1)
			"----" A 0 A_SetUserVar("user_swander_cd", 0)
			"----" A 0 A_JumpIf(user_stuck_det > 15, "MoveSwitchToWander")			
			Goto MoveAdjustSpeeds			
			
			
		MoveWander:
			// the new movement mode using A_Wander and a stored angle
			// only get here due to getting stuck while pushing
			// P.S. *or* an NPC returning to guard position
			"----" A 0 A_SetUserVar("user_stuck_det", user_stuck_det > 0 ? user_stuck_det - 1 : 0)
			"----" A 0 A_JumpIf(!user_stuck_det && user_strafe < user_speed_limit, "MoveSwitchToThrust")
			
			
			// in this mode user_swander_cd is an accumulator retaining leftover values 
			// from previous loops to dither speed (can only move in whole A_Wander calls)
			
//			"----" A 0 A_JumpIf(user_swander_cd < 2, "MoveAdjustSpeeds")
			"----" A 0 A_SetUserVar("user_angle", angle * 100.0)
			"----" A 0 A_SetAngle(user_strafing_angle)
			Goto MoveWanderPerformMovement
			
		MoveWanderPerformMovement:
			
			"----" A 0 A_Wander // moves Speed map units forward per this function call
			
			// assumes Speed 5
			"----" A 0 A_SetUserVar("user_swander_cd", 0) //user_swander_cd - 5) // may go negative!
//			"----" A 0 A_JumpIf(user_swander_cd > 0, "MoveWanderPerformMovement")
			Goto MoveWanderAfterMovement
			
		MoveWanderAfterMovement:
			"----" A 0 A_SetUserVar("user_strafing_angle", angle)
			"----" A 0 A_SetAngle(user_angle * 0.01)
			Goto MoveAdjustSpeeds
			
		MoveSwitchToThrust:
			"----" A 0 A_SetUserVar("user_move_wander", 0)
			"----" A 0 ACS_NamedExecuteAlways("SkulltagTransmitSynStateToClient")
			Goto MoveThrust
		
		MoveSwitchToWander:
			"----" A 0 A_SetUserVar("user_swander_cd", 0)
			"----" A 0 A_SetUserVar("user_move_wander", 1)
			
			"----" A 0 A_JumpIf(user_syn_mode == 1 && (user_charge || user_ambush), 2)
			//"----" A 0 A_FaceTarget
			"----" A 0 A_SetUserVar("user_angle", angle * 100.0)
			
			// now select the initial strafing angle according the desired movement direction
			// (will change from hitting obstacles anyway)
			//"----" A 0 A_FaceTarget
			"----" A 0 A_JumpIf(user_backpedal < -2, "MoveSTWBumrush")
			"----" A 0 A_JumpIf(user_backpedal > 2, 4)
			"----" A 0 A_JumpIf(user_rightward_vel > 300, "MoveSTWRight")
			"----" A 0 A_JumpIf(user_rightward_vel < -300, "MoveSTWLeft")
			"----" A 0 A_Jump(256, "MoveSTWLeft", "MoveSTWRight")
			// backpedal:
			"----" A 0 A_SetAngle(angle + 180 + Random(-3 * user_strafe, 3 * user_strafe))
			Goto MoveSTWFinish
		MoveSTWLeft:
			"----" A 0 A_SetAngle(angle + 90)
			Goto MoveSTWFinish
		MoveSTWRight:
			"----" A 0 A_SetAngle(angle - 90)
			Goto MoveSTWFinish
		MoveSTWBumrush:	
			"----" A 0 A_SetAngle(angle + Random(-3 * user_strafe, 3 * user_strafe))
			Goto MoveSTWFinish
		MoveSTWFinish:	
			"----" A 0 A_SetUserVar("user_strafing_angle", angle)
			"----" A 0 A_SetAngle(user_angle * 0.01)
			"----" A 0 ACS_NamedExecuteAlways("SkulltagTransmitSynStateToClient")
			Goto MoveWander
			
		MoveAdjustSpeeds:
			// calculates desired speeds from the current threat factor and distance to target
			// NPC player avoidance logic also goes here
			
			"----" A 0 A_SetUserVar("user_strafe", user_strafe < user_thr_acc / 10 ? user_thr_acc / 10 : user_strafe) // sideways dodge from threat sense
			"----" A 0 A_SetUserVar("user_strafe", user_strafe < user_speed_limit ? user_strafe : user_speed_limit)
						
			//"----" A 0 A_JumpIf((user_syn_mode == 3 || user_syn_mode == 1) && user_player_num, "MoveNPCSpecific")
			
			//MoveAdjustSpeedsContinue:	
			// user_thr_acc is capped at 255, thus speed is capped at 25 -- VERY fast
			// but each dodge-roll eats 100 off user_thr_acc (and each flinch adds 100)
			
			"----" A 0 A_JumpIf(user_thr_chaaarge, "MoveAdjSpForw")
			"----" A 0 A_JumpIfCloser(user_thr_hrr, "MoveAdjSpFleeHRR") // *no* sight check
			"----" A 0 A_JumpIfCloser(user_too_close_range, "MoveAdjSpBack")
			
			Goto MoveFinish
			
		MoveAdjSpForw:
			// fists, chainsaw: 150% speed. Berserk: 200% speed.
			//"----" A 0 A_SetUserVar("user_backpedal", - ((user_weapon == 2 ? 8 : (user_weapon == 1 || user_weapon == 3 ? 6 : 4)) + user_maradeur))
			"----" A 0 A_SetUserVar("user_backpedal", -6)
			Goto MoveFinish	
			
		MoveAdjSpBack:
			// max (user_thr_acc / 10, 4 + user_maradeur)
			"----" A 0 A_SetUserVar("user_backpedal", user_thr_acc / 10 > 4 ? user_thr_acc / 10 : 4)
			Goto MoveFinish
			
		MoveAdjSpFleeHRR:
			// max (user_thr_acc / 10, 10)
			"----" A 0 A_SetUserVar("user_backpedal", user_thr_acc / 10 > 10 ? user_thr_acc / 10 : 10)
			Goto MoveFinish			
			
		MoveFinish:	
			"----" A 0
			Goto AnimPhase			
			
			
			
			
			
			
		AnimPhase:  // must have the duration of exactly 1 tic.
			"----" A 0 A_JumpIf(user_in_air, "AnimJump")

			"----" A 0 A_JumpIf((user_dx * user_dx) + (user_dy * user_dy) > 20, "AnimFastWalk")
			"----" A 0 A_JumpIf(user_dx || user_dy, "AnimSlowWalk")
			// standing still
			//"----" A 0 A_SetUserVar("user_anim_frame", 0)
			//"----" A 0 A_SetUserVar("user_anim_frame_time", 0)
			// standing still:
			"----" A 1 A_Jump(256, "AnimFrame1")
			Wait
		AnimSlowWalk:
			"----" A 0 A_SetUserVar("user_anim_frame_time", user_anim_frame_time + 1)
			"----" A 0 A_JumpIf(user_anim_frame_time >= 4, "AnimNextFrame")
			Goto AnimFrame
		AnimFastWalk:
			"----" A 0 A_SetUserVar("user_anim_frame_time", user_anim_frame_time + 2)
			"----" A 0 A_JumpIf(user_anim_frame_time >= 4, "AnimNextFrame")
			Goto AnimFrame
		AnimNextFrame:
			"----" A 0 A_SetUserVar("user_anim_frame_time", 0)
			"----" A 0 A_SetUserVar("user_anim_frame", user_anim_frame >= 4 ? 0 : user_anim_frame + 1)
			"----" A 0 A_JumpIf(user_footstep_mask & (1 << user_anim_frame), "AnimFootstep") // a bit mask check
		AnimFrame:
			"----" A 0 A_JumpIf(user_anim_frame <= 0, "AnimFrame1")
			"----" A 0 A_JumpIf(user_anim_frame == 1, "AnimFrame2")
			"----" A 0 A_JumpIf(user_anim_frame == 2, "AnimFrame3")
			"----" A 0 A_JumpIf(user_anim_frame == 3, "AnimFrame4")
			"----" A 1 // emergency fallback (Zandronum client WILL reach here, it ignores jumps)
			Goto WeaponPhase
		AnimJump:
			"----" A 0 A_SetUserVar("user_anim_frame", 0)
			"----" A 0 A_SetUserVar("user_anim_frame_time", 0)
			"----" A 0 A_Jump(256, "AnimFrameJ")
			"----" A 1 // emergency fallback (Zandronum client WILL reach here, it ignores jumps)
			Goto WeaponPhase
				
		AnimFootstep:		
			"----" A 0 // does nothing by default
			Goto AnimFrame	
			
		WeaponPhase: // must have zero duration
		
			// manage weapon cooldown -- independent of syn mode
			"----" A 0 A_JumpIf(!user_wp_cooldown, 2)
			"----" A 0 A_SetUserVar("user_wp_cooldown", user_wp_cooldown > 0 ? user_wp_cooldown - 1 : 0)
		
			"----" A 0 A_JumpIf(user_syn_mode == 1, "WeaponMissile")
			"----" A 0 A_JumpIf(user_has_los && (user_syn_mode == 2 || user_syn_mode == 3), "Missile") // insta-switch to firing
			"----" A 0 A_JumpIf(user_syn_mode == 2 || user_syn_mode == 3, "WeaponLoiter")
			"----" A 0 A_JumpIf(user_syn_mode == 2 || user_syn_mode == 4, "WeaponJumping")
			Goto ThreatSensePhase // Error, unknown syn state. Do nothing.
			
		WeaponLoiter: // the synth state used purely for movement purposes. 
			//  Employs A_Chase to switch to the missile state.
			"----" A 0 A_SetUserVar("user_angle", angle * 100.0) // CHF_DONTMOVE fucks the angle up
			"----" A 0 A_Chase("Missile", "Missile", CHF_DONTMOVE) // Standard missile chance. 
			"----" A 0 A_SetAngle("user_angle", angle * 0.01)
			Goto WeaponFinish
			
		WeaponJumping: // a unique hack for managing the jumping animation. 
			// May fire a snap shot by switching to syn mode 1 (missile)
		
			"----" A 0 A_JumpIf(user_wp_cooldown > 0 || user_syn_mode == 1, "WeaponFinish") // no further action needed
			"----" A 0 A_JumpIfTargetInLOS(1, 130, JLOSF_DEADNOJUMP)
			Goto WeaponFinish
			// user_in_air is managed in the Movement phase
			// no snap shots if melee
			// no snap shots for bfg9k
			"----" A 0 A_JumpIf(user_in_air > 6 && !user_stand_still, 1) 
		
			Goto WeaponFinish //<-- jumps over this goto here (which is not a frame but rather between the frames)
			
			// An instaneous snap cheat shot the moment we ascend
			// 	 over that 64-high crate on the apex of our arch,
			//   our deadly super shotgun in hand, 
			//   to rain death on the hapless player.
			
			"----" A 0 A_SetUserVar("user_syn_mode", 1) // switch to syn mode 1, Missile. Will proceed charging, firing and so on.
			"----" A 0 A_FaceTarget
			"----" A 0 ACS_NamedExecuteAlways("SkulltagTransmitSynStateToClient") // the Zandronum game engine does never sync user variables nor monsters' inventories
			"----" A 0 A_SetUserVar("user_shots", user_burst_length)
			"----" A 0 A_SetUserVar("user_notarget_cooldown", 0)
			"----" A 0 A_SetUserVar("user_shot_cooldown", 0)
			"----" A 0 A_SetUserVar("user_charge", user_charge_time)
			"----" A 0 A_SetUserVar("user_best_d", 0) // invalidate user_best_p
			"----" A 0 A_FaceTarget
			"----" A 0 A_SetUserVar("user_best_a", angle * 182.0444)
			Goto WeaponFinish
			
		WeaponClearTarget:
			"----" A 0 A_ClearTarget
			Goto WeaponFinish
			
		WeaponMissile: // our equivalent of the Missile state. Consists of charging, firing and ambushing
		
			// If we got here it means we are committed to firing.
			// No dawdling, no loitering, only cooldown can delay us and only ambusing can divert us.
			
			"----" A 0 A_JumpIf(user_wp_cooldown > 0, "WeaponFinish") // do nothing
			
			"----" A 0 A_JumpIf(user_shots <= 0, "WeaponFinish") // we are done.
			// After all shots are fired, the ball is on the Threat Sense phase's side, 
			//   which exits the synth loop to See -- maybe, via a parting dodge-roll.
			
			// For *all* weapons except the bfg, "charge" is actually a pre-fire pause
			//   to give the marines survivable reaction times
			
			"----" A 0 A_JumpIf(user_ambush > 0, "WeaponAmbushing") // assumes charge is full
			
			"----" A 0 A_JumpIf(user_charge < user_charge_time, "WeaponCharging")
			
			Goto WeaponFiring
			
		WeaponCharging:
			"----" A 0 A_SetUserVar("user_charge", user_charge + 1)
			"----" A 0 A_JumpIf(user_charge % 4 == 1, "WpnPobeForTheBest") // every 4 tics (because has to reset d before each probing)
			Goto WeaponChargingFinish
			
		WpnPobeForTheBest:	
			"----" A 0 A_JumpIf(!user_has_los, 2)
			"----" A 0 A_SetUserVar("user_best_a", angle * 182.0444)
			"----" A 0 A_SetUserVar("user_best_d", 0) // also invalidates user_best_p
			"----" A 0 A_JumpIf(!CallAcs("FBD_RequestExoticManeuver", 2), "WeaponChargingFinish")
			// Probes take at least one tic to launch and run their script
			"----" A 0 A_CustomMissile("SynthMarinesBestAngleProbeCentral", user_muzzle_z - 6, 0, user_best_a * 0.005493164, CMF_ABSOLUTEANGLE | CMF_OFFSETPITCH | (user_best_d ? CMF_ABSOLUTEPITCH : CMF_SAVEPITCH), user_best_d ? user_best_p * 0.005493164 : 0)
			"----" AAAAA 0 A_CustomMissile("SynthMarinesBestAngleProbe", user_muzzle_z - 6, 0, user_best_a * 0.005493164 + Random(-100, 100) * 0.01 * (1.0 + 0.003 * (user_rightward_vel < 0 ? - user_rightward_vel : user_rightward_vel)), CMF_ABSOLUTEANGLE | (user_best_d ? CMF_ABSOLUTEPITCH : CMF_OFFSETPITCH) | CMF_SAVEPITCH, (user_best_d ? user_best_p * 0.005493164 : 0) + Random(-100, 100) * 0.03) 
			//Screw. Pitch. Random(-30, 30) * 0.01 * (1.0 + 0.01 * (user_forward_vel < 0 ? - user_forward_vel : user_forward_vel)))
			Goto WeaponChargingFinish
			
		WeaponChargingFinish:
			"----" A 0
			Goto WeaponChargingSFX	// will proceed to weapon-specific effect states that jump to WeaponFinish
			
		WeaponFiring:
			"----" A 0 A_JumpIf(!user_shot_cooldown, 2)
			"----" A 0 A_SetUserVar("user_shot_cooldown", user_shot_cooldown > 0 ? user_shot_cooldown - 1 : 0)
			"----" A 0 A_JumpIf (user_shots > 0 && user_shot_cooldown > 0, "WeaponFinish") // pause between shots of a burst
			Goto WeaponFire
			
		WeaponFire:	
			//"----" A 0 A_SetUserVar("user_ambush", 0) // need keep it to prevent double-ambushing. Cleared in WeaponFireReally.
			"----" A 0 A_SetUserVar("user_shots", user_shots > 0 ? user_shots - 1 : 0)
			"----" A 0 A_SetUserVar("user_shot_cooldown", user_shots > 0 ? user_fire_period : 0)
			"----" A 0 A_JumpIfInTargetInventory("ChainguyguyContinue", 1, "WeaponFireAutoaimed") // otherwise they migrate due to circle-strafing and then fire at a random wall because their firing direction stays locked
			"----" A 0 A_JumpIf(CallAcs("FBD_TargetIsInvisible"), "WeaponBlindfire")
			"----" A 0 A_JumpIf(!user_has_los, "WeaponBlindfire") 
			"----" A 0 A_JumpIfTargetInLOS("WeaponFireAutoaimed")
		WeaponBlindfire:
			"----" A 0 A_SetAngle(user_best_a * 0.005493164)
			
			// in case of having LOS but target being invisible, updating til the end ofthe current loop
			"----" A 0 A_JumpIf(!user_has_los, 2)
			"----" A 0 A_SetUserVar("user_has_los", 0) 
			
			// Ambush is not applicable for bfg nor for melee weapons.
			// And, of course, this check is only valid before firing the first shot!
			"----" A 0 A_JumpIf(user_ambush || user_stand_still || user_weapon <= 3 || user_shots < user_burst_length, "WeaponFireReally") 
			
			//"----" A 0 A_Jump(user_ambush_chance, "WeaponAmbushInstead")
			Goto WeaponFireReally	
			
		WeaponFireAutoaimed:
			"----" A 0 A_FaceTarget
			"----" A 0 A_SetUserVar("user_best_a", angle * 182.0444)
			"----" A 0 A_JumpIf(user_shots > 0, "WeaponKeepProbing")
			Goto WeaponFireReally
			
		WeaponKeepProbing:
			"----" A 0 A_JumpIf(!CallAcs("FBD_RequestExoticManeuver", 2), "WeaponFireReally")
			// these probes will come bearing gifts when it is time to fire the next shot in the burst
			"----" A 0 A_CustomMissile("SynthMarinesBestAngleProbeCentral", user_muzzle_z - 6, 0, user_best_a * 0.005493164, CMF_ABSOLUTEANGLE | CMF_OFFSETPITCH | CMF_SAVEPITCH, 0)
			"----" AAAAA 0 A_CustomMissile("SynthMarinesBestAngleProbe", user_muzzle_z - 6, 0, user_best_a * 0.005493164 + Random(-100, 100) * 0.01 * (1.0 + 0.003 * (user_rightward_vel < 0 ? - user_rightward_vel : user_rightward_vel)), CMF_ABSOLUTEANGLE | (user_best_d ? CMF_ABSOLUTEPITCH  : CMF_OFFSETPITCH) | CMF_SAVEPITCH, (user_best_d ? user_best_p * 0.005493164 : 0) + Random(-100, 100) * 0.03) 
			Goto WeaponFireReally
			
		WeaponAmbushInstead:
			"----" A 0 A_SetUserVar("user_ambush", 1)
			Goto WeaponFinish			
			
		WeaponAmbushing: // freeze, ready to fire a snap shot
			"----" A 0 A_JumpIfTargetInLOS(3, 0, JLOSF_DEADNOJUMP)
			"----" A 0 A_SetUserVar("user_notarget_cooldown", user_notarget_cooldown + 1)
			"----" A 0 A_JumpIf(user_notarget_cooldown > user_ambush_duration && !user_in_air, "WeaponCancelAmbush")
			Goto WeaponFinish
			
			// snap shot from ambush - 8 tics of LOS, very fast
			"----" A 0 A_JumpIfTargetInLOS(3, 0, JLOSF_DEADNOJUMP)
			"----" A 0 A_SetUserVar("user_ambush", user_ambush + 1)
			"----" A 0 A_JumpIf(user_ambush > 8, "WeaponFire")
			
			// special effects, only applicable to minigun (spinning sound)
			//"----" A 0 A_JumpIf(user_weapon != 7, "WeaponFinish")
			//"----" A 0 A_PlaySound("CHAINSPI", CHAN_WEAPON, 1, 1)
			Goto WeaponFinish
			
		WeaponCancelAmbush:
			"----" A 0 A_SetUserVar("user_ambush", 0)
			"----" A 0 A_SetUserVar("user_shots", 0)
			"----" A 0 A_SetUserVar("user_charge", 0)
			"----" A 0 A_SetUserVar("user_syn_mode", 2)
			Goto WeaponFinish

		WeaponFireReally: 
			"----" A 0 A_SetUserVar("user_ambush", 0)
			"----" A 0 A_JumpIf(user_weapon >= 31 && user_weapon <= 34, "WpnFire_MonsterDefined")
			"----" A 1 A_Jump(256, "MeleeAttack") // inheritance-aware jump
			Wait // Zandronum client will ignore jumps and keep repeating the last frame
			
		OneMoreShot: // can be used by weapon fire states to increase burst length
			"----" A 0 A_JumpIf(user_shots < user_burst_length, 1)
			Goto WeaponAfterFiring
			"----" A 0 A_SetUserVar("user_shots", user_shots + 1)
			Goto WeaponAfterFiring
			
		WeaponAfterFiring:
		
			"----" A 0 A_SetUserVar("user_best_d", 0) // also invalidates user_best_p
			
			// A specific hack, after original BD chaingun guys, to keep firing the minigun at a killed player to splatter him
			// This shit goes on for 200 tics! See player.txt, Death.MonsterMinigun
			"----" A 0 A_JumpIf(user_weapon != 7 || user_shots >= user_burst_length, 2)
			"----" A 0 A_JumpIfInventory("ChainguyguyContinue", 1, "OneMoreShot", AAPTR_TARGET) 
			
			// randomizing burst length
			// only when one shot in burst is left -- to minimize parasitic recursion by making sure 
			// one more shot is called no more than one time per loop
			"----" A 0 A_JumpIf(user_burst_length < 2 || user_shots != 1, 2) 
			"----" A 0 A_Jump(user_weapon == 7 && user_has_los ? 224 : (user_has_los ? 160 : 64), "OneMoreShot") // Beware of recursion!
			
			"----" A 0 A_JumpIf(user_shots, "WeaponFinish")
			"----" A 0 A_SetUserVar("user_charge", 0)
			"----" A 0 A_SetUserVar("user_wp_cooldown", user_weapon_cooldown_time)
			
			"----" A 0 A_JumpIf(CallAcs("GetIsTargetDead"), "KilledMyTarget") // exits the synth loop
			
			"----" A 0 A_SetUserVar("user_syn_mode", 2)
			
		WeaponFinish:
			"----" A 0
			"----" A 0 A_JumpIf(user_syn_mode == 1 && !user_ambush && user_nag_period && user_nag_cooldown < user_nag_period / 3, "BattleCry")
			Goto ThreatSensePhase
			
		AfterBattleCry:
			"----" A 0 A_SetUserVar("user_nag_cooldown", Random(user_nag_period / 2, user_nag_period))
			Goto ThreatSensePhase
			



		ThreatSensePhase:  // must have zero duration
			"----" A 0 A_JumpIf(user_thr_cooldown, "ThreatCooldown")
			"----" A 0 A_SetUserVar("user_thr_chaaarge", 0)//user_default_weapon <= 3 && !user_maradeur ? 1 : 0)
			
			// Step 1: who is our target? How powerful is he?
			
			"----" A 0 A_JumpIfInTargetInventory("TargetIsAGreatTerribleBoss", 1, "Threat_OhCrap")
			"----" A 0 A_JumpIfInTargetInventory("TargetIsABoss", 1, "Threat_Boss")
			"----" A 0 A_JumpIfInTargetInventory("IsInATank", 1, "Threat_Boss")
			
			"----" A 0 A_JumpIfInTargetInventory("TargetIsAMiniBoss", 1, "Threat_Miniboss")
			"----" A 0 A_JumpIfInTargetInventory("IsPlayer", 1, "Threat_Player")
			"----" A 0 A_JumpIfInTargetInventory("TargetIsAChaosMarine", 1, "Threat_Fellow")
			"----" A 0 A_JumpIfInTargetInventory("TargetIsAMarine", 1, "Threat_Fellow")
			
			// take mancubi very seriously, we are critically vulnerable to their flame spam:
			"----" A 0 A_JumpIfInTargetInventory("TargetIsAMancubus", 1, "Threat_Boss") 
			// knights and barons only because higher forms trigger boss checks above:
			"----" A 0 A_JumpIfInTargetInventory("TargetIsABruiser", 1, "Threat_Bruiser") 
			Goto Threat_Lame
			
			
		Threat_Lame:
			"----" A 0 A_SetUserVar("user_thr_mul", 0)
			"----" A 0 A_SetUserVar("user_thr_hrr", 0)
			"----" A 0 A_SetUserVar("user_thr_min", 0)
			Goto ThreatCalc
		Threat_Player: 
			
			
			// player's threat varies greatly with the weapon he holds:
			
			// only re-evaluate when we can see him:
			"----" A 0 A_JumpIfTargetInLOS(1, 0, JLOSF_DEADNOJUMP)
			Goto ThreatCalc		
			
			"----" A 0 A_JumpIfInventory("QPowerQuadDamage",1,"Threat_OhCrap",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("PowerTransformBaron",1,"Threat_Player_SSG",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("PowerTransformRevenant",1,"Threat_Player_Explo",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("FistsSelected",1,"Threat_Player_Fists",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("HasBarrel",1,"Threat_Player_Explo",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("RevenantLauncherSelected",1,"Threat_Player_Explo",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("RocketLauncherSelected",1,"Threat_Player_Explo",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("GrenadeLauncherSelected",1,"Threat_Player_Explo",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("BFG10kSelected",1,"Threat_Player_BFG10k",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("BFGSelected",1,"Threat_Player_BFG",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("UnmakerSelected",1,"Threat_Player_Unmaker",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("RailGunSelected",1,"Threat_Player_Railgun",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("SSGSelected",1,"Threat_Player_SSG",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("sawSelected",1,"Threat_Player_Stayback",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("AxeSelected",1,"Threat_Player_Stayback",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("DragonslayerSelected",1,"Threat_Player_Dragonslayer",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("MG42Selected",1,"Threat_Player_MG42",AAPTR_TARGET)			
			"----" A 0 A_JumpIfInventory("HasCuttingWeapon",1,"Threat_Player_Stayback",AAPTR_TARGET)
			"----" A 0 A_JumpIfInventory("FlameCannonSelected",1,"Threat_Player_Flameth",AAPTR_TARGET)
			
			//"----" A 0 A_JumpIfInventory("",1,"Threat_Player_",AAPTR_TARGET)
			
			// default (all other weapons):
			"----" A 0 A_SetUserVar("user_thr_mul", 9) // dangerous like a mini-boss but no hrr
			"----" A 0 A_SetUserVar("user_thr_hrr", 0)
			"----" A 0 A_SetUserVar("user_thr_min", 50)
			Goto ThreatCalc
		Threat_Player_Fists:
			"----" A 0 A_JumpIfInventory("PowerStrength",1,"Threat_Player_Stayback",AAPTR_TARGET) // yikes, he has berserk
			"----" A 0 A_SetUserVar("user_thr_mul", 4) // meh
			"----" A 0 A_SetUserVar("user_thr_hrr", 0)
			"----" A 0 A_SetUserVar("user_thr_min", 0)
			Goto ThreatCalc
		Threat_Player_SSG:
			"----" A 0 A_SetUserVar("user_thr_mul", 49)
			"----" A 0 A_SetUserVar("user_thr_min", 98)
			"----" A 0 A_SetUserVar("user_thr_hrr", 450)
			Goto ThreatCalc				
		Threat_Player_Railgun:
			"----" A 0 A_SetUserVar("user_thr_mul", 99)
			"----" A 0 A_SetUserVar("user_thr_min", 202)
			"----" A 0 A_SetUserVar("user_thr_hrr", 0)
			Goto ThreatCalc
		Threat_Player_Unmaker:	
			"----" A 0 A_SetUserVar("user_thr_mul", 99)
			"----" A 0 A_SetUserVar("user_thr_min", 202)
			Goto ThreatCalc			
		Threat_Player_BFG10k:	
			// Up close it's explosive, bumrush. Far away it's a bfg 9000.
			"----" A 0 A_JumpIfTargetInLOS("Threat_Player_Explo", 0, JLOSF_DEADNOJUMP, 400)
			"----" A 0 A_SetUserVar("user_thr_mul", 99)
			"----" A 0 A_SetUserVar("user_thr_min", 202)
			"----" A 0 A_SetUserVar("user_thr_hrr", 1200)
			Goto ThreatCalc
		Threat_Player_BFG:
			"----" A 0 A_SetUserVar("user_thr_mul", 99)
			"----" A 0 A_SetUserVar("user_thr_min", 202)
			"----" A 0 A_SetUserVar("user_thr_hrr", 1200) // but not if we have chainsaw selected
			Goto ThreatCalc
		Threat_Player_Dragonslayer: 
			"----" A 0 A_SetUserVar("user_thr_mul", 99)
			"----" A 0 A_SetUserVar("user_thr_min", 202)
			"----" A 0 A_SetUserVar("user_thr_hrr", 400)
			Goto ThreatCalc
		Threat_Player_MG42:
			"----" A 0 A_SetUserVar("user_thr_mul", 99)
			"----" A 0 A_SetUserVar("user_thr_min", 202)
			"----" A 0 A_SetUserVar("user_thr_hrr", 2000)
			Goto ThreatCalc			
		Threat_Player_Stayback:
			//has berserk or chainsaw! ignore aim but keep distance of at least 400
			"----" A 0 A_SetUserVar("user_thr_mul", 9)
			"----" A 0 A_SetUserVar("user_thr_min", 0)
			"----" A 0 A_SetUserVar("user_thr_hrr", 400)
			Goto ThreatCalc
		Threat_Player_Flameth: //has flame cannon or flamethrower
			"----" A 0 A_SetUserVar("user_thr_mul", 29)
			"----" A 0 A_SetUserVar("user_thr_min", 60)
			"----" A 0 A_SetUserVar("user_thr_hrr", 500)
			"----" A 0 A_JumpIfCloser(500, 1)
			Goto ThreatCalc
			"----" A 0 A_SetUserVar("user_thr_min", 198)
			Goto ThreatCalc			
		Threat_Player_Explo: // has a rocket launcher, grenade launcher, bfg 10k, revenant launcher or a barrell.
			"----" A 0 A_SetUserVar("user_thr_mul", 19)
			"----" A 0 A_SetUserVar("user_thr_min", 98)
			// fall further back if distance, close in aggressively if close enough
			"----" A 0 A_JumpIfTargetInLOS(2, 0, JLOSF_DEADNOJUMP, 500) // if closer than 500, rush player instead
			"----" A 0 A_SetUserVar("user_thr_hrr", 650)
			Goto ThreatCalc
			// close up quickly
			"----" A 0 A_SetUserVar("user_thr_hrr", 0)
			"----" A 0 A_SetUserVar("user_thr_chaaarge", 1)	
			"----" A 0 A_SetUserVar("user_thr_min", 102)
			Goto ThreatCalc
		Threat_Fellow:
			"----" A 0 A_SetUserVar("user_thr_mul", 9) // dangerous like a mini-boss but no hrr
			"----" A 0 A_SetUserVar("user_thr_min", 70)
			"----" A 0 A_SetUserVar("user_thr_hrr", 0)
			Goto ThreatCalc
		Threat_Bruiser:
			"----" A 0 A_SetUserVar("user_thr_mul", 19)
			"----" A 0 A_SetUserVar("user_thr_min", 98)
			"----" A 0 A_SetUserVar("user_thr_hrr", 400)
			Goto ThreatCalc
		Threat_Miniboss:
			"----" A 0 A_SetUserVar("user_thr_mul", 29)
			"----" A 0 A_SetUserVar("user_thr_min", 98)
			"----" A 0 A_SetUserVar("user_thr_hrr", 650) // cannot set higher, hexen dodging stops working
			Goto ThreatCalc
		Threat_Boss:
			"----" A 0 A_SetUserVar("user_thr_mul", 39)
			"----" A 0 A_SetUserVar("user_thr_min", 102)
			"----" A 0 A_SetUserVar("user_thr_hrr", 1200) // want to be as far from him as possible
			Goto ThreatCalc
		Threat_OhCrap:
			"----" A 0 A_SetUserVar("user_thr_mul", 49)
			"----" A 0 A_SetUserVar("user_thr_min", 198)
			"----" A 0 A_SetUserVar("user_thr_hrr", 2000) // stay in cover fearfully
			Goto ThreatCalc
		ThreatClearNPC:
			"----" A 0 A_SetUserVar("user_thr_mul", 0)
			"----" A 0 A_SetUserVar("user_thr_min", 0)
			"----" A 0 A_SetUserVar("user_thr_hrr", 0) // stay in cover fearfully
			Goto ThreatCalc			
		
		ThreatCalc:

			// Step 2: is he aiming in our direction? (accumulate threat factor over time)
			
			// horizontal only: checking for vertical aim is beyond this scripting language
			"----" A 0 A_JumpIfInTargetLOS("ThreatCalcAimingAtUs", 5, JLOSF_DEADNOJUMP | JLOSF_CLOSENOSIGHT, user_thr_hrr > 1200 ? user_thr_hrr : 1200, user_melee_range)
			
			"----" A 0 A_JumpIfInTargetLOS("ThreatCalcLookingAtUs", 25, JLOSF_DEADNOJUMP | JLOSF_CLOSENOSIGHT, user_thr_hrr > 700 ? user_thr_hrr : 700, user_melee_range)
			"----" A 0 A_JumpIf(user_thr_acc > user_thr_min, "ThreatWpnSwitch")
			"----" A 0 A_SetUserVar("user_thr_acc",	user_thr_min)		
			
			Goto ThreatWpnSwitch // the threat accumulator will degrade over time if no los or the target is facing away from us
		ThreatCalcAimingAtUs:	
			"----" A 0 A_SetUserVar("user_thr_acc", (user_thr_min > user_thr_acc ? user_thr_min : user_thr_acc) + 2 + user_thr_mul * 2)
		ThreatCalcLookingAtUs:
			"----" A 0 A_SetUserVar("user_thr_acc", (user_thr_min > user_thr_acc ? user_thr_min : user_thr_acc) + 1 + user_thr_mul)
			Goto ThreatWpnSwitch
		
		ThreatWpnSwitch:
			// Step 3: do we need to switch our weapon ?
			
			// This state can only choose between default and melee.
			// Maradeur's is *much* more sophisticated.
			
			// not legible for weapon switch
			"----" A 0 A_JumpIf(user_wp_cooldown || user_in_air || (user_syn_mode == 1 && (user_shots || (user_charge && user_stand_still))), "ThreatFinish")
				
			"----" A 0 A_JumpIf(user_weapon >= 4, "ThrWeHaveRangedWeaponSelected")
			Goto ThrWeHaveMeleeWeaponSelected
		ThrWeHaveMeleeWeaponSelected:
			"----" A 0 A_JumpIf(user_default_weapon <= 3, "ThreatFinish") // do nothing 
				// if we only have a melee weapon (the fist, berserk and chainsaw marines)
			//Five melee misses force a switch to ranged weapon
			"----" A 0 A_JumpIfInventory("MeleeMiss", 5, "ThrSwitchToRanged")
			
			// If the opponent has a Horrible Rape Radius defined, that forces a switch to ranged:
			"----" A 0 A_JumpIf(user_thr_hrr, "ThrSwitchToRanged")
			"----" A 0 A_JumpIfCloser(user_melee_range + 96, "ThreatFinish") // don't switch while in the melee range
			Goto ThrSwitchToRanged
			
		ThrWeHaveRangedWeaponSelected:
			"----" A 0 A_JumpIf(user_thr_hrr, "ThreatFinish") // NEVER switch to melee 
				// if the opponent has a Horrible Rape Radius defined!
			"----" A 0 A_JumpIfInventory("MeleeMiss", 1, "ThreatFinish") // do not switch to melee 
				// until we forget the trauma of not hitting out target (decreased with each attack)
				// Even a single miss prevents us from switching to melee
				//  but 5 are required to force switch to our ranged weapon 
				//  regardless of distance - such a nice histeresis loop.
			"----" A 0 A_JumpIfTargetInLOS("ThrSwitchToMelee", 130, JLOSF_DEADNOJUMP, user_melee_range)
			Goto ThreatFinish
			
		ThrSwitchToRanged:
			"----" A 0 A_SetUserVar("user_see_after_wp_sw", 0) // return to the synth loop afterwards
			"----" A 0 A_SetUserVar("user_weapon", user_default_weapon)
			Goto WeaponSwitch

		ThrSwitchToMelee:
			"----" A 0 A_SetUserVar("user_see_after_wp_sw", 0) // return to the synth loop afterwards
			"----" A 0 A_SetUserVar("user_weapon", user_melee_weapon)
			Goto WeaponSwitch
			
	
		ThreatFinish:
			"----" A 0 A_SetUserVar("user_thr_cooldown", 5)
			"----" A 0 A_SetUserVar("user_thr_acc", user_thr_acc > 255 ? 255 : user_thr_acc - 10)
			"----" A 0 A_JumpIf(!user_wp_cooldown, "MaybeEndSynthLoop")
			
			// if the targeit is aiming at us, and our weapon is on cooldown (we just fired, then dodge-roll 
			// with probability matching the threat level:
			"----" A 0 A_JumpIfInTargetLOS(1, 18, JLOSF_DEADNOJUMP, user_thr_hrr > 1200 ? user_thr_hrr : 1200)
			Goto MaybeEndSynthLoop
			"----" A 0 A_Jump(user_thr_acc, "ThreatDodgeRollOnWpCldwn")
			Goto MaybeEndSynthLoop
			
		ThreatDodgeRollOnWpCldwn:
			"----" A 0 A_SetUserVar("user_thr_acc", user_thr_acc > 100 ? user_thr_acc - 100 : 0)	
			Goto ShuffleFromPain	
			
		ThreatCooldown:
			"----" A 0 A_SetUserVar("user_thr_cooldown", user_thr_cooldown - 1)
			Goto MaybeEndSynthLoop	

		MaybeEndSynthLoop:
			
			// missile mode: stay another 6 tics to assure animation consistency
			"----" A 0 A_JumpIf(user_syn_mode == 1 && user_loiter_count > 5 && !user_ambush && user_wp_cooldown <= (user_weapon_cooldown_time > 6 ? user_weapon_cooldown_time - 6 : 0), "ExitSynthLoop")
			"----" A 0 A_JumpIf(user_syn_mode == 3 && user_loiter_count > 30, "ExitSynthLoop")
			"----" A 0 A_JumpIf(user_syn_mode >= 2 && user_syn_mode <= 4 && user_loiter_count > 90, "ExitSynthLoop")

			Goto SynthLoop	

		WeaponSwitch:
			// does NOT affect weapon cooldown
			//"----" A 0 A_SetUserVar("user_wp_cooldown", 0)
			
			"----" A 0 A_SetUserVar("user_charge", 0)
			"----" A 0 A_SetUserVar("user_shots", 0)
			"----" A 0 A_SetUserVar("user_ambush", 0)
			"----" A 0 A_SetUserVar("user_shot_cooldown", 0)
			"----" A 0 A_SetUserVar("user_anim_frame", 0)	
			"----" A 0 A_SetUserVar("user_anim_frame_time", 0)
			"----" A 0 A_JumpIf(user_weapon, 2)
			"----" A 0 A_SetUserVar("user_weapon", user_default_weapon)
			
			"----" A 0 A_JumpIf(user_weapon >= 4, 3)
			"----" A 0 A_TakeInventory("MeleeMiss", 99)
			"----" A 0 A_TakeInventory("MeleeHitSuccess", 99)
			
			// If this is Zandronum client-server multiplayer, and this is running on the server,
			//   will rlay this via running SkulltagClientsideWeaponSwitch, which command would be
			//   transmitted to the client over the network thus syncing this user variable
			//   (the clientside script then forces the clientside instance of this monster into
			//   this WeaponSwitch state)
			// Otherwise, user variables on the server and the client are independent
			"----" A 0 ACS_NamedExecuteAlways("SkulltagTransmitWeaponSwitchToClient", 0, user_weapon,0,0)
			
			"----" A 0 A_JumpIf(user_weapon == 31, "WeaponSwitch_UberSniper")
			"----" A 0 A_JumpIf(user_weapon == 32, "WeaponSwitch_UberZoldat")
			"----" A 0 A_JumpIf(user_weapon == 33, "WeaponSwitch_Scorzeny")
			"----" A 0 A_JumpIf(user_weapon == 34, "WeaponSwitch_SSNazi")
			
			"----" A 1 A_PlaySound("KYSNDBZZ", CHAN_VOICE) // error, unknown weapon
			Goto WeaponSwitchFinish
			
		WeaponSwitch_UberSniper:
			"----" A 0 A_JumpIf(user_prev_wpn == 31, 2)
			"----" A 0 A_PlaySound("RELO4", CHAN_WEAPON)	
			"----" A 0 A_SetUserVar("user_ambush_duration", 75)
				// Normally chance is 0 but this applies to other paths of activating the synth loop that bypass the Missile state.
			"----" A 0 A_SetUserVar("user_ambush_chance", 96)
			"----" A 0 A_SetUserVar("user_fire_period", 0) // single-shot
			"----" A 0 A_SetUserVar("user_weapon_cooldown_time", 35)
			"----" A 0 A_SetUserVar("user_burst_length", 1)
			"----" A 0 A_SetUserVar("user_muzzle_z", 43) 
			"----" A 0 A_SetUserVar("user_charge_time", 35) // a whole second -- not actually charging, just aiming
			"----" A 0 A_SetUserVar("user_melee_range", 1) // will NOT engage in meelee
			"----" A 0 A_SetUserVar("user_too_close_range", 1200) // prefers extreme distances
			"----" A 0 A_SetUserVar("user_stand_still", 1) // canNOT instafire during a jump
			Goto WeaponSwitchFinish			
			
		WeaponSwitch_UberZoldat:
			"----" A 0 A_JumpIf(user_prev_wpn == 32, 2)
			"----" A 0 A_PlaySound("CLIPIN", CHAN_WEAPON)	
			"----" A 0 A_SetUserVar("user_ambush_duration", 75)
			"----" A 0 A_SetUserVar("user_ambush_chance", 128)
			"----" A 0 A_SetUserVar("user_fire_period", 2) // n-sane fire rate
			"----" A 0 A_SetUserVar("user_burst_length", 12) // this is *minimum*! Can add randomly
			"----" A 0 A_SetUserVar("user_weapon_cooldown_time", 10)
			"----" A 0 A_SetUserVar("user_muzzle_z", 35) 
			"----" A 0 A_SetUserVar("user_charge_time", 15) // half a second
			"----" A 0 A_SetUserVar("user_melee_range", 1) // will NOT engage in meelee
			"----" A 0 A_SetUserVar("user_too_close_range", 500) // prefers medium distances		
			"----" A 0 A_SetUserVar("user_stand_still", 1) // canNOT instafire during a jump
			Goto WeaponSwitchFinish
			
		WeaponSwitch_Scorzeny:
			"----" A 0 A_JumpIf(user_prev_wpn == 33, 2)
			"----" A 0 A_PlaySound("CLIPIN", CHAN_WEAPON)	
/*
	moved to SetupDefaults because various skill versions vary this
			"----" A 0 A_SetUserVar("user_ambush_duration", 150)
			"----" A 0 A_SetUserVar("user_ambush_chance", 96)
			"----" A 0 A_SetUserVar("user_fire_period", 1) // n-sane fire rate
			"----" A 0 A_SetUserVar("user_burst_length", 12) // this is *minimum*! Can add randomly
			"----" A 0 A_SetUserVar("user_charge_time", 35) // a full second
			"----" A 0 A_SetUserVar("user_weapon_cooldown_time", 35) // a full second
			"----" A 0 A_SetUserVar("user_too_close_range", 700) // prefers medium distances		
*/			
			"----" A 0 A_SetUserVar("user_muzzle_z", 43) 
			"----" A 0 A_SetUserVar("user_melee_range", 1) // will NOT engage in meelee
			"----" A 0 A_SetUserVar("user_stand_still", 1) // canNOT instafire during a jump
			Goto WeaponSwitchFinish	

		WeaponSwitch_SSNazi:
			"----" A 0 A_JumpIf(user_prev_wpn == 34, 2)
			"----" A 0 A_PlaySound("CLIPIN", CHAN_WEAPON)	
			"----" A 0 A_SetUserVar("user_ambush_duration", 105)
				// Normally chance is 0 but this applies to other paths of activating the synth loop that bypass the Missile state.
			"----" A 0 A_SetUserVar("user_ambush_chance", 96)
			"----" A 0 A_SetUserVar("user_fire_period", 4)
			"----" A 0 A_SetUserVar("user_weapon_cooldown_time", 15)
			"----" A 0 A_SetUserVar("user_burst_length", 4)
			"----" A 0 A_SetUserVar("user_muzzle_z", 41) 
			"----" A 0 A_SetUserVar("user_charge_time", 10) // a third of a second -- not actually charging, just aiming
			"----" A 0 A_SetUserVar("user_melee_range", 1) // will NOT engage in meelee
			"----" A 0 A_SetUserVar("user_too_close_range", 700) // prefers medium distances
			"----" A 0 A_SetUserVar("user_stand_still", 1) // canNOT instafire during a jump
			Goto WeaponSwitchFinish				
			
		WeaponSwitchFinish:
			"----" A 0 A_SetUserVar("user_prev_wpn", user_weapon)
			"----" A 0 A_JumpIf(!user_awakened, "Stand")
			"----" A 0 A_JumpIf(user_see_after_wp_sw == 1, "See")
			"----" A 0 A_JumpIf(user_see_after_wp_sw == 2, "CheckForFatality") //"IdleLoop")
			Goto Missile //SynthLoop

		WanderCycle:
			"----" A 0 A_SetUserVar("user_wander", user_wander > 0 ? user_wander - 1 : 0)

			"----" A 0 A_JumpIf(user_weapon == 31, "Wander_UberSniper")
			"----" A 0 A_JumpIf(user_weapon == 32, "Wander_UberZoldat")
			"----" A 0 A_JumpIf(user_weapon == 33, "Wander_Scorzeny")
			"----" A 0 A_JumpIf(user_weapon == 34, "Wander_SSNazi")
			
		
		Wander_ErrorUnknownWeapon:	
			"----" AAAA 2 A_Wander
			"----" A 0 A_Look
			"----" AAAA 2 A_Wander
			"----" A 0 A_Look
			"----" AAAA 2 A_Wander
			"----" A 0 A_Look
			"----" AAAA 2 A_Wander
			"----" A 0 A_Look
			Goto Idle
			
		Wander_UberSniper:
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 43)
			UZOS BBBB 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 43)
			UZOS CCCC 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 43)
			UZOS DDDD 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 43)
			UZOS AAAA 2 A_Wander
			"----" A 0 A_Look
			Goto Idle			

		Wander_UberZoldat:
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 43)
			UZOL BBBB 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 43)
			UZOL CCCC 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 43)
			UZOL DDDD 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 43)
			UZOL AAAA 2 A_Wander
			"----" A 0 A_Look
			Goto Idle
			
		Wander_Scorzeny:
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 45)
			"----" A 0 A_PlaySound("KYBHOOF1")
			KYSZ BBBB 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 45)
			KYSZ CCCC 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 45)
			"----" A 0 A_PlaySound("KYBHOOF1")
			KYSZ DDDD 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 45)
			KYSZ AAAA 2 A_Wander
			"----" A 0 A_Look
			Goto Idle

		Wander_SSNazi: // the dastardly nazis only have 3 frames of walk animation while the synth code designed for four!
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 3, 3, 38)
			NAZI BBBB 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 3, 3, 38)
			NAZI CCCC 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 3, 3, 38)
			NAZI AAAA 2 A_Wander
			"----" A 0 A_Look
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 3, 3, 38)
			NAZI BBBB 2 A_Wander
			"----" A 0 A_Look
			Goto Idle		
			
		ChaseFrame1:
			// the a_chase in animation doesn't jump to missile, only moves -- while a_chase afterwards jumps but doesn't move

			"----" A 0 A_JumpIf(user_weapon == 31, "ChaseFrame1_UberSniper")
			"----" A 0 A_JumpIf(user_weapon == 32, "ChaseFrame1_UberZoldat")
			"----" A 0 A_JumpIf(user_weapon == 33, "ChaseFrame1_Scorzeny")
			"----" A 0 A_JumpIf(user_weapon == 34, "ChaseFrame1_SSNazi")
			
			"----" AA 1 A_Chase("", "") // // error, unknown weapon
			Goto ChaseLoopContinue
		ChaseFrame1_UberSniper:
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 43)
			UZOS DD 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame1_UberZoldat:
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 43)
			UZOL DD 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame1_Scorzeny:
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 45)
			"----" A 0 A_PlaySound("KYBHOOF1")
			KYSZ DD 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame1_SSNazi:
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 3, 3, 38)
			NAZI CC 1 A_Chase("", "")
			Goto ChaseLoopContinue			
			
		ChaseFrame2:
			// the a_chase in animation doesn't jump to missile, only moves -- while a_chase afterwards jumps but doesn't move

			"----" A 0 A_JumpIf(user_weapon == 31, "ChaseFrame2_UberSniper")
			"----" A 0 A_JumpIf(user_weapon == 32, "ChaseFrame2_UberZoldat")
			"----" A 0 A_JumpIf(user_weapon == 33, "ChaseFrame2_Scorzeny")
			"----" A 0 A_JumpIf(user_weapon == 34, "ChaseFrame2_SSNazi")
			
			"----" AA 1 A_Chase("", "") // // error, unknown weapon
			Goto ChaseLoopContinue
		ChaseFrame2_UberSniper:
			UZOS AA 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame2_UberZoldat:
			UZOL AA 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame2_Scorzeny:
			KYSZ AA 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame2_SSNazi:
			NAZI AA 1 A_Chase("", "")
			Goto ChaseLoopContinue				

		ChaseFrame3:
			// the a_chase in animation doesn't jump to missile, only moves -- while a_chase afterwards jumps but doesn't move

			"----" A 0 A_JumpIf(user_weapon == 31, "ChaseFrame3_UberSniper")
			"----" A 0 A_JumpIf(user_weapon == 32, "ChaseFrame3_UberZoldat")
			"----" A 0 A_JumpIf(user_weapon == 33, "ChaseFrame3_Scorzeny")
			"----" A 0 A_JumpIf(user_weapon == 34, "ChaseFrame3_SSNazi")
			
			"----" AA 1 A_Chase("", "") // // error, unknown weapon
			Goto ChaseLoopContinue
		ChaseFrame3_UberSniper:
			UZOS BB 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame3_UberZoldat:
			UZOL BB 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame3_Scorzeny:
			"----" A 0 A_PlaySound("KYBHOOF1")
			KYSZ BB 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame3_SSNazi:
			NAZI BB 1 A_Chase("", "")
			Goto ChaseLoopContinue				
			
		ChaseFrame4:
			// the a_chase in animation doesn't jump to missile, only moves -- while a_chase afterwards jumps but doesn't move

			"----" A 0 A_JumpIf(user_weapon == 31, "ChaseFrame4_UberSniper")
			"----" A 0 A_JumpIf(user_weapon == 32, "ChaseFrame4_UberZoldat")
			"----" A 0 A_JumpIf(user_weapon == 33, "ChaseFrame4_Scorzeny")
			"----" A 0 A_JumpIf(user_weapon == 34, "ChaseFrame4_SSNazi")
			
			"----" AA 1 A_Chase("", "") // // error, unknown weapon
			Goto ChaseLoopContinue
		ChaseFrame4_UberSniper:
			UZOS BB 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame4_UberZoldat:
			UZOL BB 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame4_Scorzeny:
			KYSZ CC 1 A_Chase("", "")
			Goto ChaseLoopContinue
		ChaseFrame4_SSNazi:
			NAZI BB 1 A_Chase("", "")
			Goto ChaseLoopContinue				
			
		WeaponChargingSFX:
			"----" A 0 //A_JumpIf(user_weapon == X, "WpnChrgSFX_X")
			Goto WeaponFinish
	
	}
}	

			