#=============================================================================== #Global states (not halted by pause/superPause, no helper limitations) #=============================================================================== [StateDef -4] if stateNo = 100 && roundState != 2 && aiLevelF { changeState{value: 0; ctrl: 1} } # this ZSS AI file is used to define and implement AI for kung fu man. #it can also be used a guide for you to create your own AI using IKEMEN GO. #------------|dis values|------------------------------------------------------- #This code ensures that in tag mode or simul mode, the "p2bodydist x" value accounts for #the actual nearest enemy immediately. ignoreHitPause if !isHelper { #activeplayer dist mapSet{map: "enemydx"; value: (pos x - enemyNear,pos x) * (-facing)} #activeplayer bodydist grounded if stateType != A && enemyNear,stateType != A { mapSet{map: "enemybdx"; value: ((pos x - enemyNear,pos x) + (const(size.ground.front) + enemyNear,const(size.ground.front)) * (facing)) * (-facing)} } else if stateType = A && enemyNear,stateType != A { #activeplayer bodydist - p1 in air, p2 on ground mapSet{map: "enemybdx"; value: ((pos x - enemyNear,pos x) + (const(size.air.front) + enemyNear,const(size.ground.front)) * (facing)) * (-facing)} } else if stateType != A && enemyNear,stateType = A { #activeplayer bodydist - p1 on ground, p2 in air mapSet{map: "enemybdx"; value: ((pos x - enemyNear,pos x) + (const(size.ground.front) + enemyNear,const(size.air.front)) * (facing)) * (-facing)} } else if stateType = A && enemyNear,stateType = A { #activeplayer bodydist - both in air mapSet{map: "enemybdx"; value: ((pos x - enemyNear,pos x) + (const(size.air.front) + enemyNear,const(size.air.front)) * (facing)) * (-facing)} } } #This code will calculate a "velocity" even if the opponent uses posadds for movement. ignoreHitPause if gameTime%2 = 0 { mapSet{map: "ppx"; value: enemyNear,pos x} } #------------|Juggle point|----------------------------------------------------- #Currently, juggle points cannot be detected, so this hackish way of doing so will help the AI #determine what juggles it has left to use for combo attacks ignoreHitPause if moveHit = 2 && !isHelper && cond(numTarget, target,hitFall, 0) { if hitCount = 1 || map(jug) = 0 { if stateNo = 200 { let jug = 1; } else if stateNo = 600 { let jug = 2; } else if stateNo = 630 { let jug = 3; } else if stateNo = 230 || stateNo = 210 || stateNo = 610 || stateNo = 640 || stateNo = 1000 || stateNo = 1010 || stateNo = 1050 || stateNo = 1060 || stateNo = 1070 || stateNo = 1100 || stateNo = 1110 || stateNo = 1200 || stateNo = 1210 || stateNo = 1400 || stateNo = 1410 || stateNo = 3000 || stateNo = 3050 { let jug = 4; } else if stateNo = 240 || stateNo = 400 || stateNo = 430 { let jug = 5; } else if stateNo = 410 || stateNo = 1020 || stateNo = 1420 || stateNo = 1220 || stateNo = 1120 { let jug = 6; } else if stateNo = 440 { let jug = 7; } mapAdd{map: "jug"; value: $jug} } } if enemyNear,moveType != H || enemyNear,stateNo = 5040 || enemyNear,stateNo = [5200, 5210] { mapSet{map: "jug"; value: 0} } #=============================================================================== #Global states (commands) #=============================================================================== [StateDef -1] #This is used to prevent undesirable actions after getting up from a knock down for a short amount of time if anim = 5120 || roundState != 2 { #getuprecoverytime mapSet{map: "gurt"; value: 10} } #global AI loop ignoreHitPause if aiLevelF && roundState = 2 && !standby { #prevent default jump behavior assertSpecial{flag: nojump; flag2: noairjump} #prevent default walk behavior assertSpecial{flag: nowalk; flag2: nobrake} #------------|AI variable declarations|----------------------------------------- let inrange = 0; #short hand p2bodydist x let p2dx = map(enemybdx); #short hand p2bodydist y let p2dy = p2BodyDist Y; #get all lights let lights = stateNo = 200 || stateNo = 230 || stateNo = 400 || stateNo = 430; #get all heavies that can cancel let heavy = stateNo = 210 || stateNo = 240 || stateNo = 410; #opponent is not in air or lying down let grounded = enemyNear,stateType = S || enemyNear,stateType = C; #Super cancel flag let SC = stateNo = [1000, 1420] && stateType != A && map(canCombo); #CC - CanCombo, this variable checks and returns the current amount of hitstun the opponent is in. # because KFM has no projectiles, we can easily detect if he has a target to accomplish this. let CC = cond(numTarget, cond(!enemyNear,hitFall, target,getHitVar(hittime), getHitVar(fall.recovertime)), 0); #typically you could check the velocity of the opponent to determine how fast they are moving #however, if they use posadds to move instead, the vel will remain 0. Using some trickery we can determine the position based velocity #using this code below because if the opponent has moved position on the x-axis, we can check 1 frame later to determine how far they moved. #if they have not moved, we can try to track velocity instead. let trvelx = cond((abs(map(ppx)) - abs(enemyNear,pos x)) = 0 || enemyNear,vel x > (abs(map(ppx)) - abs(enemyNear,pos x)), enemyNear,vel x, (abs(map(ppx)) - abs(enemyNear,pos x))); #game specific values let nojug = enemyNear,anim = 5120 || enemyNear,stateNo = 5040 && enemyNear,ctrl || enemyNear,stateNo = 52 && enemyNear,time < 3 && enemyNear,prevStateNo = 5040; #how many points do we have to juggle with? let jugpt = map(jug); let hitfall = enemyNear,hitFall || $CC > 8; #Allows the AI to possibly link attacks if they have less recovery than the opponent. if ctrl && !enemyNear,ctrl && (enemyNear,getHitVar(hittime) > 0) { let AI_JI = enemyNear,getHitVar(hittime); } #things to do in neutral(not attacking) #Neutral attacks and combo conditions are separated to prevent accidental code preventing either from working #properly. if (ctrl && stateNo != 105 || stateNo = 20 || stateNo = 100 || stateNo = 1310 || stateNo = 1330 || stateNo = 1330 || stateNo = 1350) { if stateType != A { #--|Reversals|----------------------------------------------------------- if (enemyNear,moveType = A) && enemyNear,time > 1 { #------------|SUPERS|--------------------------------------------------- if power >= 1500 { if ($p2dx = [-10, (35+floor($trvelx*.4)*3)] &&(!$grounded && $p2dy = [-80+(floor(enemyNear,vel y*.4)*-5), -15] || $grounded)) { changeState{value: 3050} } #Tripple Kung Fu Palm #This first condition checks for if the opponent is in range of the attack hitting, it adds the opponents current velocity #to determine if they would be hit by them moving closer while attacking. This can be set to any range if you are using this #as an example. if ($p2dx = [30*($hitfall)-36, (90+floor($trvelx*.4)*5)] && ($p2dy = [-50+(floor(enemyNear,vel y*.4)*-5), -15] || $grounded) && (enemyNear,stateNo != 5040 && enemyNear,moveType != H || !$grounded && $p2dy = [-50, -15])) && power >= 1000 { changeState{value: 3000} } } #------------------------------------------------------------------------- #Kung Fu Knee if enemyNear,stateType = A && $p2dx = [40*($hitfall)-30, (50+floor($trvelx*.4)*10)] && $p2dy = [-80+(floor(enemyNear,vel y*.4)*-5), -60+($hitfall)*40] && (enemyNear,stateNo != 5040 && enemyNear,moveType != H || !$grounded && $p2dy = [-60, -15]) && (!map(gurt) || $p2dx > 30) && random <= (350 * (aiLevelF ** 2 / 48.0)) { if power >= 500 && random%3 = 1 && $p2dy < -70 { let version2 = 1070; } else if enemyNear,vel x > 0 && $p2dy < -70 { let version2 = 1060; } else { let version2 = 1050; } changeState{value: $version2} } #----------------------------------------------------------------------- #Kung Fu Blocking #This is a command parry that kung fu man has, from an AI perspective, it can be challenging to indicate when it should be used. #For now, this is the most case handling we will attempt. We start by checking if they are moving or what the attack distance of their #current attack is. We can use that math loosely to determine where their attack is. Because this can make fighting challenging, it is disabled #unless the aiLevelF is 5 or higher if $p2dx = [-15, 30+floor($trvelx*.4)*10+floor(enemyNear,const(size.attack.dist)*.5)] && $p2dy = [-50+(floor(enemyNear,vel y *.6)*-10), 0] && random <= (335 * (aiLevelF ** 2 / 48.0)) && enemyNear,moveType = A && aiLevel > 4 { changeState{value: cond(enemyNear,stateType != C,1300,1320)} } } #----------------------------------------------------------------------- #anti air specials are used where it is safe for kfm to try to stop the opponent from jumping in and attacking #because of how they can connect, even on a blocking opponent, it leaves kfm moderately safe and is considered #minimal risk to perform. #Kung Fu Upper #We reduce the chance of this happening to 25% to prevent overusage. if enemyNear,stateType = A && $p2dx = [5*($hitfall)-20, (30+floor($trvelx*.4)*20)] && (enemyNear,stateNo != 5040 && enemyNear,moveType != H || !$grounded && $p2dy = [-80+(floor(enemyNear,vel y*.6)*-5), -40+($hitfall)*30]) && (!map(gurt) || $p2dx > 30) && random <= (450 * (aiLevelF ** 2 / 48.0)) { #1/3 chance to use ex move when power is at least half of one meter if power >= 500 && random%3 = 1 { let version = 1120; #use this for advancing enemies } else if enemyNear,vel x > 0 { let version = 1110; #default version } else { let version = 1100; } changeState{value: $version} } #----------------------------------------------------------------------- #anti air normals if random <= (420 * (aiLevelF ** 2 / 48.0)) && $p2dx < 45 && $p2dy = [-70+(floor(enemyNear,vel y*.4)*-5), -20] && !$nojug && $jugpt = 0 { changeState{value: 410} } #----------------------------------------------------------------------- #throw if random <= (310 * (aiLevelF ** 2 / 48.0)) && stateType = S && stateNo != 100 && (enemyNear,moveType != H || enemyNear,stateNo = [120, 131]) && (map(AI_JI) < 2) && $p2dx < 30 && $grounded { changeState{value: 800} } #----------------------------------------------------------------------- #blocking if (enemyNear,moveType = A && prevStateNo != [1300, 1350] && stateNo != [1300, 1350] && inGuardDist && random <= (700 * (aiLevelF ** 2 / 48.0)) || enemyNear,numProj > 0 && random < (440 * (aiLevelF ** 2 / 48.0))) && $p2dx > -20 && enemyNear,stateType != L && (ctrl || stateNo = 20 || stateNo = 100) || (enemyNear,numProj >= 1) { assertSpecial{flag: autoguard} changeState{value: 120} } #----------------------------------------------------------------------- #this attack is a special case attack, the angle of attack indicates it can be used #to stop crouching attacking opponents preemptively, so kfm will try to do so when possible. #used to hit crouching attacking opponents from a distance if ($p2dx = [35, 55+(floor($trvelx*.4)*5)]) && enemyNear,stateType = C && (enemyNear,moveType = A) && random <= (450 * (aiLevelF ** 2 / 48.0)) { changeState{value: 240} } #----------------------------------------------------------------------- #light attacks (200,230,400,430) if $p2dx < 55 + (floor($trvelx * .4) * 5) && !$AI_JI && !$nojug && (!map(gurt) || $p2dx > 35) && ($p2dx > 25 || random <= (225 * (aiLevelF ** 2 / 48.0)) || enemyNear,stateType = A) && (enemyNear,stateNo != [1025, 1028] || (enemyNear,moveType != H || $CC > 3 && $hitfall && enemyNear,stateNo != [1025, 1028])) { if ($grounded || $p2dy = [-40+(floor(enemyNear,vel y*.4)*-10), -15]) && $p2dx < 45 { let att = cond($p2dy < -40 || enemyNear,stateType = S, 200, 400); if $att = 400 && $p2dx < 35 + (floor($trvelx * .4) * 5) || $att != 400 { changeState{value: $att} } } else if ($p2dx > 25 || random <= (225 * (aiLevelF ** 2 / 48.0))) && $grounded { let att = cond($p2dy > -10 || enemyNear,stateType = S, 430, 230); if $att = 430 && $p2dx < 45 + (floor($trvelx * .4) * 5) || $att != 430 { changeState{value: $att} } } } #----------------------------------------------------------------------- #heavy attacks (210,240) #we do not include 440 or 410 here because they are defined elsewhere in a more #specialized way that focuses on what they are capable of doing in a match. if $p2dx < 60 + (floor($trvelx * .4) * 5) && !$AI_JI && (!$nojug || $p2dy > -10) && (!map(gurt) || $p2dx > 35) && random <= (425 * (aiLevelF ** 2 / 48.0)) && (enemyNear,stateNo != [1025, 1028] || enemyNear,moveType != H) { if ($grounded || $p2dy = [-50 + (floor(enemyNear,vel y*.6)*-10), -25]) { let att = cond($p2dy > -10 || enemyNear,stateType = S, 240, 210); if $att = 240 && $p2dx < 45 + (floor($trvelx * .4) * 5) || $att != 240 { changeState{value: $att} } } } #----------------------------------------------------------------------- #jump in landing attacks can be used to start combos from a successful jump attack (600-640) #Using the $AI_JumpIn variable, we can inform the AI about how much time they have to #start a combo by linking a ground attack. if $AI_JI > 9 && $p2dx = [35, 60] && $grounded { changeState{value: cond($p2dx < 50, 240, 210)} } if $AI_JI > 3 && $p2dx <= 55 && $grounded { changeState{value: cond(enemyNear,stateType = S, cond($p2dx > 40, 230, 200), cond($p2dx < 30, 400, 430))} } #----------------------------------------------------------------------- #The term "poke" is used to refer to attacks that can usually attack opponents from a safe distance #without high risk. The attacks below meet that criteria but can be changed if more attacks are added later. #pokes if $p2dx = [45, 60] && enemyNear,moveType != H && $grounded && random < (250 * (aiLevelF ** 2 / 48.0)) { if $p2dx = [30, 60+(floor($trvelx*.4)*5)] && random%4 = 0 { let att2 = 210; } else if $p2dx = [30, 50+(floor($trvelx*.4)*5)] && random%4 = 1 { let att2 = 240; } else if $p2dx = [30, 60+(floor($trvelx*.4)*5)] && enemyNear,stateType = S { let att2 = 440; } if $att2 > 0 { changeState{value: $att2} } } #----------------------------------------------------------------------- #OTG - attacks that can hit a fallen opponent. if (enemyNear,stateType = L || enemyNear,stateNo = 52) && $jugpt < 13 && $p2dx = [-2, 45] && (!$nojug || enemyNear,stateNo = 52) { changeState{value: cond($jugpt < 8 && enemyNear,time < 20, 440, 430)} } #End of file: stateType != A #=========================================================================== #This section of AI handles attacks that are done in the air. } else if stateType = A && enemyNear,stateType != L { #kung fu blocking - air if $p2dx = [-15, 35+floor($trvelx*.4)*5+floor(enemyNear,const(size.attack.dist)*.5)] && $p2dy = [-20+(floor(enemyNear,vel y*.4)*-5), 30+(floor(vel y*.4)*5)] && random <= (600 * (aiLevelF ** 2 / 48.0)) && enemyNear,moveType = A { changeState{value: 1340} } #cross up #currently this character has no way to do a cross up(attack that hits behind opponent while you jump) #so this is commented, however you could add that ability right now! If you do you can use this code #to define it. #let cu = $p2dx = [-65, 10]; #if $cu && vel x > 0 && (enemyNear,stateNo = 5120 || $grounded && !$nojug) && vel y > 0 { # ChangeState{value: 630} #} #------------|air normal attacks|--------------------------------------- #we do not want kfm to try to hit an attacking opponent using specials because this typically means kfm will lose to it. #However, if it's a lower AI level it's ok to make mistakes, or if kfm is behind the opponent anyway. if (enemyNear,hitDefAttr != SCA,SA || facing != enemyNear,facing || aiLevelF < 6) && random <= (700 * (aiLevelF ** 2 / 48.0)) { #These attacks will have variable y distance detection depending on if the opponent is standing or crouching, it is not perfect #but the illusion of intelligence is all that matters. We do not want kfm to attack characters in a recovering (state 5040) state. #heavy attacks are given priority as they have bigger rewards, but light attacks are faster so both will be taken into account. if (frontEdgeBodyDist < 50 || $p2dx = [-5, (55+(floor($trvelx * .4)*5) + (floor(vel x * .4)*20))]) && ($p2dy > 30 || $p2dy < 0) && $p2dy = [5,40 + ((enemyNear,stateType = S || enemyNear,stateNo = [5115,5122])*40) + ((enemyNear,stateType = C)*25)] && (vel y > 0 || !$grounded && !$nojug) { changeState{value: 640} } if (frontEdgeBodyDist < 50 || $p2dx = [-8, (45+(floor($trvelx * .4)*5) + (floor(vel x * .4)*5))]) && ($p2dy > 30 || $p2dy < 0) && $p2dy = [-20,45 + ((enemyNear,stateType = S || enemyNear,stateNo = [5115,5122])*40) + ((enemyNear,stateType = C)*25)] && (vel y > 0 || !$grounded && !$nojug) { changeState{value: 610} } if (frontEdgeBodyDist < 50 || $p2dx = [-15, (40+(floor($trvelx * .4)*5) + (floor(vel x * .4)*20))]) && $p2dy = [-20,35+((enemyNear,stateType = S || enemyNear,stateNo = [5115,5122])*40) + ((enemyNear,stateType = C)*25)] && (vel y > 0 || !$grounded && !$nojug) { changeState{value: 600} } if (frontEdgeBodyDist < 50 || $p2dx =[-15, (30+(floor($trvelx * .4)*5) + (floor(vel x * .4)*25))]) && $p2dy = [-80,35+((enemyNear,stateType = S || enemyNear,stateNo = [5115,5122])*40) + ((enemyNear,stateType = C)*25)] && (vel y > 0 || (!$grounded) && (!$nojug) || $hitfall) { changeState{value: 630} } } #End of file: stateType = A #=========================================================================== } #End of file: ctrl #=============================================================================== #this section of AI is meant for attacks to be done after an attack defined above connects either as a hit #or blocked by the opponent. } else if moveContact = [1, 3] && hitPauseTime = 0 && stateType != A { #--------------------------------------------------------------------------- #These are freeform random combo fillers. They have very basic conditions and #do not break the human pattern of combos. lights can be used to build distance before #finishing combos as well as giving additional damage. #lights if $jugpt < 6 && random < (700 * (aiLevelF ** 2 / 48.0)) { if $p2dx < 20 && moveContact && $lights { if random%2 || enemyNear,stateType = A { changeState{value: cond($p2dy < -18, 200, 400)} } else { changeState{value: cond($p2dx < 25, 430, 230)} } } #--------------------------------------------------------------------------- #light to other #this block will build the middle piece of combos. Sometimes a super will occur if the condition #is met. if $p2dx < 85 && moveHit && $lights && !$nojug && random < (600 * (aiLevelF ** 2 / 48.0)) { if $hitfall && $jugpt = [8, 10] && $p2dx = [-8, 35] && $p2dy > -75 && $p2dy != 0 && power > 1000 { changeState{value: 3050} } #We must ensure kfm's attack will combo by checking how much hittime the opponent has remaining. if (random%5 < 3 || enemyNear,stateType = A) && (enemyNear,stateType != L || $p2dy != 0) && $p2dx < 60 { if $CC > 8 { changeState{value: cond($p2dy < -30 || $p2dx > 40, 210, 240)} } else if $p2dx < 35 { changeState{value: 410} } } else { changeState{value: 440} } } } #--------------------------------------------------------------------------- #this block will determine how and if kfm will cancel into his various specials. The criteria is that the hitpause of the current attack #is over and the opponent is either not falling or in the air in a possible juggle state. It also requires at least 11 frames of hittime #to ensure the special will connect and the combo will continue unless they are in the air where fall.recovertime is prioritized instead. if ($heavy || $lights && (!$grounded && $p2dy < -10 & $p2dx > 55 || $p2dx >55)) && (moveHit) && ($hitfall || $grounded || $CC > 11) && random < (800 * (aiLevelF ** 2 / 48.0)) { #using our somewhat accurate juggle point system, we are specifying that we only want moves to be used #if we haven't used more than 8 juggle points. if $jugpt <= 8 { #if we have at least 7 frames of hittime from the current attack, we #can cancel into the specials below without fail. For lower levels, #we randomly cancel 50% of the time. if $CC > 7 || aiLevel < 5 && random%2 { #the range of kung fu palm requires at least 120 pixels of space to #connect without missing. The opponent needs to at least be 50 pixels in the air #while falling to ensure the attack juggles. Or they are not in the air at all. if $p2dx = [40, 120] && ($p2dy = [10, -50] || $grounded) { #1/3 chance of using ex version if possible. if power > 450 && $grounded && random%3 = 0 { let spver = 1020; #if we have at least 9 frames of hittime } else if $CC > 9 && $p2dx < 85 { let spver = 1010; } else { #at minimum we use weak kung fu palm let spver = 1000; } changeState{value: $spver} #if the opponent is closer, we can use higher damaging moves that deal more stun. #such as kung fu zankou } else if $p2dx < 40 && ($p2dy = [10, -50] || $grounded) { if power > 450 && $grounded && random%3 = 0 { let spver = 1420; } else if $CC > 9 && $p2dx > 40 { let spver = 1410; } else { let spver = 1400; } changeState{value: $spver} } } #if the opponent is in the air and they are in range, kfm will try to use kung fu knee if !$grounded && $p2dy = [-80+(floor(enemyNear,vel y*.4)*-5), -25] && $CC > 6 && $p2dx < 40 { if power > 450 && $grounded && random%3 = 0 { let spver = 1070; } else if $p2dx > 40 || random%2 { let spver = 1060; } else { let spver = 1050; } changeState{value: $spver} } # if kfm is about to run out of juggle points, he will try to use kung fu blow to deal a # devastating end to a combo. } else if $jugpt = [8, 12+(power < 1000)] { #finishers if $p2dx = [-8, 80] && $p2dy = [-55+(floor(enemyNear,vel y*.4)*-5), -35] { changeState{value: 1200 + (random%2) * 10} } } } #--------------------------------------------------------------------------- #This is used to determine if kfm should cancel his supers attacks into hyper attacks #as a reminder $SC is used to identify the same check a human player has to meet to perform this #cancel. we then check if a heavy attack or even a light attack can be used if the opponent is #close to losing. This will gurantee kfm's victory usually. if ($SC || ($heavy && (enemyNear,life < 350) || $lights)) && moveHit && $jugpt < 14 && random < (700 * (aiLevelF ** 2 / 48.0)) { if power >= 1000 { if $p2dx = [-5, 25] && ($p2dy = [-75, -1] || $grounded) { changeState{value: 3050} } if $p2dx = [-5, 80] && ($p2dy = [-40+(floor(enemyNear,vel y*.6)*-5), -25] || $grounded) { changeState{value: 3000} } } } #End of file: moveContact #=============================================================================== } #------------|Kung Fu Knee follow up|------------------------------------------- #If there was more follow ups to his kung fu knee, this is the place to handle it #The criteria matches the same rule as a non-cpu. Refer to state 1051 to verify. #This is placed outside of the main two blocks above because it is considered a special case outlier. if (stateNo = 1051 || stateNo = 1061 || stateNo = 1071) && (moveHit || moveContact && aiLevel < 6) && vel y < -1 { if stateNo = [1050, 1069] { changeState{value: 1055} } else { changeState{value: 1075} } } #------------|MOVEMENT|--------------------------------------------------------- #------------|walking|---------------------------------------------------------- #These are the conditions that will make kfm walk forward. mapSet{map: "AIw"; value: 0} if ((enemyNear,moveType != A) || $p2dx > 25) || (enemyNear,stateType = L && $p2dx > 70) || $AI_JI > 0 { mapSet{map: "AIw"; value: 1} } #These are the conditions that will make kfm walk backwards if backEdgeBodyDist > 40 && (enemyNear,moveType = A || enemyNear,stateType != L && $p2dx < 30) { mapSet{map: "AIw"; value: -1} } #there's a 25% chance at any time that if possible, kfm will walk a given direction with the conditions given if stateType = S && ctrl && stateNo != 100 && random < 249 && (enemyNear,moveType != A || backEdgeBodyDist < 40) && ($p2dx = [25, 120]) && map(AIw) != 0 { changeState{value: 20} } #If the AI is walking, we don't want them to stutter crouching as it looks very robotic. if map(AIw) != 0 && aiLevel > 3 { assertSpecial{flag: nocrouch} } #if the walk condition zeros out, kfm will stop walking. if map(AIw) = 0 && stateNo = 20 { printToConsole{text: "changeState{value: 0}"} changeState{value: 0; ctrl: 1} } #------------|running|---------------------------------------------------------- #These are the conditions that will make kfm run if stateType != A && (ctrl || stateNo = 20) && stateNo != 100 && random <= (396 * (aiLevelF ** 2 / 48.0)) && (enemyNear,moveType != A || backEdgeBodyDist < 40) && ($p2dx >= cond($hitfall || enemyNear,stateNo = 5300, 10, 120)) { changeState{value: 100} } #this will make kfm stop running. If you are making your own character with a stop running animation, #be sure to change this value: 0 to whatever that state is. if stateNo = 100 && ($p2dx < 40 - 20 * (!$grounded) && enemyNear,stateNo != 5040 || $p2dx < - 65 || roundState != 2) { changeState{value: 0; ctrl: 1} } #------------|jumping|---------------------------------------------------------- #this will decrement the get-up recovery-time map set above if map(gurt) > 0 { mapAdd{map: "gurt"; value: -1} } #this is to control optimal times to jump and attack on an opponent getting up from #a knock down. let p2l = enemyNear,anim = 5120 || enemyNear,stateNo = 5110 && enemyNear,time > 10; #These are the jump conditions for kfm. Starting off, kfm should not jump immediately after getting up as statistically, #it leads to the worst outcome. However, if an opponent tries to throw and kfm detects it, he will still jump. #He will also jump if the opponent is waking up from their knock down to score a hit or maintain advantageous pressure. #Lastly, he will try to jump after hitting an enemy with an attack that did not knock down. This usually puts the opponent #in state 5040 or if they are stunned (state 5300). it is worth mentioning that at lower levels kfm will not be as precise #and will leave himself open forbeginners. if stateType != A && (((!map(gurt)) && (random < (375 * (aiLevelF ** 2 / 48.0)) || enemyNear,moveType = A && aiLevelF > 6) && ($p2dx > 45 + ((enemyNear,moveType != A && $grounded) * 45) || frontEdgeBodyDist < 50 || $p2l || enemyNear,stateNo = 5040 && $p2dy > -40)) || enemyNear,hitDefAttr = SC,AT && random < (455 * (aiLevelF ** 2 / 48.0))) && ( enemyNear,hitDefAttr = SC,AT || ($p2dx = [70, 90+(floor(vel x*.4)*5)] || frontEdgeDist < 30) && enemyNear,moveType != H || $p2l && ($p2dx = [50, 75+(floor(vel x*.4)*5)] || frontEdgeDist < 60) || enemyNear,stateNo = 5040 && $p2dx = [-20, 60] || enemyNear,stateNo = 5300 && $p2dx < 40 ) { let AIJ = 1; } #this will cancel out a jump declaration if the conditions have changed to prevent bad jumping behavior. #This is usually meant as a last ditch effort to ensure a jump should be done because it is considered a #high risk action. if stateType = A || moveType = H && stateNo != [120, 155] || prevStateNo = 5120 && enemyNear,stateType = A || $p2dx < 80 && frontEdgeBodyDist > 60 && !$nojug || map(gurt) > 0 && enemyNear,hitDefAttr != SC,AT || $p2dx > 180 { let AIJ = 0; } #If the AIJumping indicator remains valid, kfm will jump if he has control. if $AIJ && (ctrl || stateNo = 20 || stateNo = 100) { changeState{value: 40} } if stateNo = 40 { sysVar(1) := 0; #We override default sysVar setting to influence jumping forward or backward if $p2dx >= 60 || (enemyNear,stateNo = 5120 || enemyNear,moveType = H) && $p2dx >= 20 || enemyNear,stateType = A && $p2dx >= 60 { sysVar(1) := 1; } if $p2dx < 15 && enemyNear,moveType = A && backEdgeBodyDist > 30 && frontEdgeBodyDist > 60 { sysVar(1) := -1; } } #------------------------------------------------------------------------------- #These are the conditions that will make kfm back dash/jump it has it's own random modifier because #we do not want him to back jump as often if stateType != A && (ctrl || stateNo = 20) && random <= (296 * (aiLevelF ** 2 / 48.0)) && backEdgeBodyDist > 40 && (enemyNear,moveType = A && $p2dx < 55 || $p2dx < 20 && enemyNear,anim = 5120 && enemyNear,backEdgeBodyDist > 60) { changeState{value: 105; ctrl: 0} } #---------|AI recover|---------------------------------------------------------- #This will let kfm recover if possible with a 20% chance at any time. if alive && canRecover && random%5 = 0 && hitFall && stateNo = 5050 { if vel y > 0 && pos y >= const(movement.air.gethit.groundrecover.ground.threshold) { changeState{value: 5200} } if vel y > const(movement.air.gethit.airrecover.threshold) { changeState{value: 5210} } } #displayToClipboard{text: "%v %v %v %v %v"; params: $p2dx, sysVar(1), $jugpt, $CC, $AI_JI} #End of file: AI }