using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using TAPI;
using Terraria;
using BaseMod;
namespace PostHardModeJungle.NPCs
{
public class Black_Panther : ModNPC
{
private Random my_rand;
public override void Initialize()
{
Random my_rand = BaseMod.BaseAI.GetSyncedRand(npc);
}
/* in .json:
* animationType= type of creature with same frames/animations (or handle manually with custom FindFrame(); npc.spriteDirection must be set there or in AI() as well)
* frameCount=as creature with same frames/animations; Main.npcFrameCount[npc.type]
* aiStyle=-1, or else it will run that AI() in addition to yours
*
* ai[0]: facing change delay; when fleeing, cannot change facing due to collision 2 ticks in a row
* ai[1]: state
* ai[2]: pounce cooldown - counts down
* ai[3]: 'bored' if at/over boredom_time: creature will ignore player and attempt to leave
* -inc if stopped, at/over boredom_time, or moonwalking
* -dec if less than boredom_time and near fullspeed
* -zero if more than boredom_cooldown or justhit
* -netupdate at exactly boredom_time (whenever boredom state changes to bored)
*/
enum State { stalking, pouncing, chasing, start_fleeing, fleeing };
public override void AI()
{
if (Main.rand.Next(60) == 0) Main.NewText("npc.direction = " + npc.direction + ", boredom = " + npc.ai[3]);
#region load state
State state = State.stalking; // need to initialaze; value not meaningful yet
if (npc.ai[1] == 0) state = State.stalking;
else if (npc.ai[1] == 1) state = State.pouncing;
else if (npc.ai[1] == 2) state = State.chasing;
else if (npc.ai[1] == 3) state = State.start_fleeing;
else if (npc.ai[1] == 4) state = State.fleeing;
#endregion
#region set up NPC's attributes & behaviors
const int boredom_time = 300; // time until it stops targeting player if blocked etc
int boredom_cooldown = 10 * boredom_time; // boredom level where boredom wears off; usually 10*boredom_time
const bool tenacious = false; // won't get bored if near target.
const float tenacious_range = 200; // what's considered 'near'
const bool hops = false; // hops when close to target like Wolf and Hellhound
const float hop_velocity = 3; // forward velocity needed to initiate hopping; usually 3
const float hop_range = 100; // less than this is 'close to target'; usually 100
const float hop_power = 4; // how hard/high offensive hops are; usually 4
float acceleration = .07f; // how fast it can speed up
float top_speed = 6; // max walking speed
const float braking_power = .2f; // %of speed that can be shed every tick when above max walking speed
const float pounce_range = 200;
const int pounce_cooldown = 180; // time to reload after starting a pounce
const int min_pounce = 30; // can try another pounce immediately if pounce ends within this time
const bool fast_cornering = false; // change direction quickly like Wolf, Hellhound, and Headless Horseman
const float fast_cornering_power = .05f; // is a braking percentage
const bool explosive_start = false; // extra acceleration when not near top speed like Hellhound
const float explosive_start_power = .1f; // how fast it can speed up
const bool hates_moonwalking = true; // gets bored at double rate from moonwalking, like unicorn ai types
bool moonwalking = false; // not jump/fall and moving backwards to facing
if (npc.velocity.Y == 0f && ((npc.velocity.X > 0f && npc.direction < 0) || (npc.velocity.X < 0f && npc.direction > 0)))
moonwalking = true;
npc.TargetClosest(false); // acquire but don't face
float npc_to_target_x = Main.player[npc.target].position.X + (float)Main.player[npc.target].width * 0.5f - npc.Center.X; // x vector to target
float npc_to_target_y = Main.player[npc.target].position.Y + (float)Main.player[npc.target].height * 0.5f - npc.Center.Y; // y vector to target
float target_dist = (float)Math.Sqrt((double)(npc_to_target_x * npc_to_target_x + npc_to_target_y * npc_to_target_y)); // distance to target
bool facing_target = (npc_to_target_x > 0 && npc.spriteDirection == 1) || (npc_to_target_x < 0 && npc.spriteDirection == -1);
bool moving_forward = (npc.velocity.X < 0f && npc.spriteDirection == -1) || (npc.velocity.X > 0f && npc.spriteDirection == 1);
bool moving_backward = (npc.velocity.X > 0f && npc.spriteDirection == -1) || (npc.velocity.X < 0f && npc.spriteDirection == 1);
float light_level = Lighting.Brightness((int)npc.Center.X >> 4, (int)npc.Center.Y >> 4);
int tile_type = (int)Main.tile[(int)npc.Center.X >> 4, (int)npc.Center.Y >> 4].type; // type of tile it's on
float pounce_power = 8;
pounce_power = pounce_power - npc_to_target_y * .02f; // increase pounce power with distance
if (pounce_power < 5f) pounce_power = 5f;
if (pounce_power > 12f) pounce_power = 12f;
#endregion
#region check if standing on a solid tile
bool standing_on_solid_tile = false;
if (npc.velocity.Y == 0f) // no jump/fall
{
int y_below_feet = (int)(npc.position.Y + (float)npc.height + 7f) / 16;
int x_left_edge = (int)npc.position.X / 16;
int x_right_edge = (int)(npc.position.X + (float)npc.width) / 16;
for (int l = x_left_edge; l <= x_right_edge; l++) // check every block under feet
{
if (Main.tile[l, y_below_feet] == null) // null tile means ??
Main.tile[l, y_below_feet] = new Tile(); // ?? this was return; in fighter AI, but saw this done elsewhere
if (Main.tile[l, y_below_feet].nactive() && TileDef.solid[(int)Main.tile[l, y_below_feet].type]) // tile exists and is solid
{
standing_on_solid_tile = true;
break; // one is enough so stop checking
}
} // END traverse blocks under feet
} // END no jump/fall
#endregion
#region state effects and transitions
bool elgible_to_jump = (npc.velocity.Y == 0f && standing_on_solid_tile && moving_forward); // same requirements as jump code
if (npc.ai[2] > 0) npc.ai[2]--; // cool down pounce
#region stalking
if (state == State.stalking)
{
npc.color = new Color(0, 0, 255, 0); // blue
npc.damage = 65; // normal dmg
npc.alpha = 255 - (int)(64f * light_level); // low visibility
acceleration = .04f; // slow speed
top_speed = 1; // slow top speed
if (npc.ai[2] <= 0 && target_dist <= pounce_range && elgible_to_jump && facing_target) // stalking -> pouncing
{ // if pounce rdy, target nearby, rdy to jump, facing target -> pounce
Main.NewText("stalking -> pouncing");
state = State.pouncing;
npc.velocity.X = 2 * npc.spriteDirection; // jump towards player
npc.velocity.Y = -pounce_power; // jump power
npc.ai[2] = pounce_cooldown;
npc.ai[3] = 0f; // not bored
npc.netUpdate = true;
}
}
#endregion
#region pouncing
else if (state == State.pouncing)
{
npc.color = new Color(255, 0, 0, 0); // red
npc.damage = 130; // bonus dmg
npc.alpha = 128 - (int)(128f * light_level); // mostly visible
acceleration = .10f; // normal speed
top_speed = 4; // limited top speed - because of midair accel this determines pounce power in x direction
if ((target_dist <= pounce_range + 100) && (npc.ai[3] < (float)boredom_time) && ((npc_to_target_y < -80 && (tile_type == 5 || tile_type == 323)) || (elgible_to_jump && facing_target && (npc.ai[2] > pounce_cooldown - min_pounce))) ) // pouncing -> re-pouncing
{ // target nearby, not bored, ((target above npc, there is a tree to boost off of)or(rdy to jump, facing target, pounced recently)) -> re-pounce/re-jump
Main.NewText("pouncing -> re-pouncing");
npc.TargetClosest(true); // target & face closest player
npc.spriteDirection = npc.direction; // face player
npc.velocity.X = 2 * npc.spriteDirection; // jump towards player
npc.velocity.Y = -pounce_power; // jump power
npc.netUpdate = true;
}
else if (((npc.velocity.Y == 0f && standing_on_solid_tile) || npc.ai[2] <= 0)) // pouncing -> chasing
{ // if landed after pounce or pounce entirely cooled down -> end pounce
Main.NewText("pouncing -> chasing");
state = State.chasing;
}
}
#endregion
#region chasing
else if (state == State.chasing)
{
if (npc.ai[3] >= (float)boredom_time) npc.color = new Color(0, 255, 255, 0); // cyan
else npc.color = new Color(0, 255, 0, 0); // green
npc.damage = 65; // normal dmg
npc.alpha = 128 - (int)(128f * light_level); // mostly visible
acceleration = .10f; // normal speed
top_speed = 6; // normal top speed
if (npc.ai[2] <= 0 && target_dist <= pounce_range && npc.velocity.Y == 0f && standing_on_solid_tile && facing_target && !moving_backward) // chasing -> pouncing
{ // if pounce rdy, target nearby, no jump/fall, facing target, moving forward -> pounce
/*Main.NewText("chasing -> pouncing");
state = State.pouncing;
if (npc.velocity.X < 2 * npc.spriteDirection) npc.velocity.X = 2 * npc.spriteDirection; // jump towards player
npc.velocity.Y = -pounce_power; // jump power
npc.ai[2] = pounce_cooldown;
npc.netUpdate = true;//*/
}
else if ((target_dist <= pounce_range + 100) && (npc.ai[3] < (float)boredom_time) && (npc_to_target_y < -80) && (tile_type == 5 || tile_type == 323) ) // chasing(jumping) -> reflect off tree -> jumping/pouncing
{ // target nearby, not bored, target above npc, there is a tree to boost off of -> re-pounce/re-jump
/*Main.NewText("chasing(jumping) -> reflect off tree -> jumping/pouncing");
if (npc.ai[2] <= 0) { state = State.pouncing; npc.ai[2] = pounce_cooldown; } // make it a pounce if possible
npc.TargetClosest(true); // target & face closest player
npc.spriteDirection = npc.direction; // face player
npc.velocity.X = 2 * npc.spriteDirection; // jump towards player
npc.velocity.Y = -pounce_power; // jump power
npc.netUpdate = true;//*/
}
else if (npc.justHit)// && npc.ai[3] < (float)boredom_time)// && my_rand.Next(5) == 0) // chasing -> start_fleeing
{ // hit, not bored, 20% chance
Main.NewText("chasing -> start_fleeing");
state = State.start_fleeing;
npc.TargetClosest(true); // target & face closest player
npc.direction = -npc.direction; // turn around(presumably away from player)
npc.ai[0] = 0f; // facing change delay
npc.ai[3] = (float)boredom_time + 1; // bored(stop chasing)
npc.netUpdate = true;//*/
}
else if (npc.ai[3] >= (float)boredom_time && target_dist > 400) // chasing -> stalking
{ // bored & no player on screen
/*Main.NewText("chasing -> stalking");
state = State.stalking;//*/
}
}
#endregion
#region start_fleeing
else if (state == State.start_fleeing) // jump once, presumably away from player
{
npc.color = new Color(192, 192, 0, 0); // dk yellow
npc.ai[3] = (float)boredom_time + 1; // bored(stop chasing)
npc.damage = 65; // normal dmg
npc.alpha = 128 - (int)(128f * light_level); // mostly visible
acceleration = .10f; // normal speed
top_speed = 6; // normal top speed
if (elgible_to_jump) // start_fleeing -> jump away -> fleeing
{
Main.NewText("start_fleeing -> jump away -> fleeing");
state = State.fleeing;
npc.velocity.X = 1 * npc.spriteDirection; // jump away from player
npc.velocity.Y = -5; // jump power
npc.ai[2] = pounce_cooldown;
npc.netUpdate = true;
}
}
#endregion
#region fleeing
else if (state == State.fleeing) // run away for a bit
{
npc.color = new Color(255, 255, 0, 0); // yellow
npc.damage = 65; // normal dmg
npc.alpha = 128 - (int)(128f * light_level); // mostly visible
acceleration = .10f; // normal speed
top_speed = 6; // normal top speed
if (npc.ai[3] < (float)boredom_time) // fleeing -> chasing
{ // not bored
Main.NewText("fleeing -> chasing");
state = State.chasing;
}
}
#endregion
#endregion
#region adjust boredom level
if (hates_moonwalking && (moonwalking && state != State.pouncing))
npc.ai[3] += 1f; // unicorns hate moonwalking
if (npc.position.X == npc.oldPosition.X || npc.ai[3] >= (float)boredom_time || (moonwalking && state != State.pouncing)) // stuck,bored,moonwalking
npc.ai[3] += 1f; // add boredom
else if (npc.ai[3] > 0f)
npc.ai[3] -= 1f; // recover from boredom
//if ((npc.justHit && !(state == State.start_fleeing || state == State.fleeing)) || npc.ai[3] > boredom_cooldown) // hit(& not fleeing) or cooled down
// npc.ai[3] = 0f;
if (npc.ai[3] == (float)boredom_time) // just became bored
npc.netUpdate = true; // ?
#endregion
#region handle tenacious and hop
float npc_to_targets_head_y = Main.player[npc.target].position.Y - npc.Center.Y;
float target_head_dist = (float)Math.Sqrt((double)(npc_to_target_x * npc_to_target_x + npc_to_targets_head_y * npc_to_targets_head_y));
if (tenacious && target_head_dist < tenacious_range)
npc.ai[3] = 0f; // won't get bored if near target.
if (hops && npc.velocity.Y == 0f && target_head_dist < hop_range && Math.Abs(npc.velocity.X) > hop_velocity && ((npc.position.X + (float)(npc.width / 2) < Main.player[npc.target].position.X + (float)(Main.player[npc.target].width / 2) && npc.velocity.X > 0f) || (npc.position.X + (float)(npc.width / 2) > Main.player[npc.target].position.X + (float)(Main.player[npc.target].width / 2) && npc.velocity.X < 0f)))
npc.velocity.Y -= hop_power; // hop when nearby
#endregion
#region target or be bored
if (npc.ai[3] < (float)boredom_time) // not bored
npc.TargetClosest(true); // target & face closest player
else // bored
{
if (npc.velocity.X == 0f)
{ // possible facing change due to collision
if (npc.velocity.Y == 0f)
{ // not moving
npc.ai[0] += 1f; // facing change delay
if (npc.ai[0] >= 2f)
{
npc.direction *= -1; // facing change
npc.spriteDirection = npc.direction;
npc.ai[0] = 0f;
}
}
} // END possible facing change due to collision
else // bored, moving in x
npc.ai[0] = 0f; // reset facing change delay
npc.directionY = -1; // upwards?
if (npc.direction == 0) // still dont know why this would be 0
npc.direction = 1; // or why to only fix while bored
} // end bored
#endregion
#region melee movement
if (npc.velocity.Y == 0f || npc.wet || (npc.velocity.X <= 0f && npc.direction < 0) || (npc.velocity.X >= 0f && npc.direction > 0))
{ // no fall/jump(traction?) or wet(swimming?) or moving forward(unicorn rocket boosters?)
if (fast_cornering && ((npc.velocity.X > 0f && npc.direction < 0) || (npc.velocity.X < 0f && npc.direction > 0))) // extra braking, faster turns?
npc.velocity.X = npc.velocity.X * (1 - fast_cornering_power); // braking
if (explosive_start && ((float)npc.direction * npc.velocity.X < top_speed / 2)) // extra acceleration when not near top speed
npc.velocity.X += explosive_start_power * npc.direction; // acceleration
if (Math.Abs(npc.velocity.X) > top_speed) // running/flying faster than top speed
{
if (npc.velocity.Y == 0f) // no jump/fall
npc.velocity *= (1f - braking_power); // decelerate
}
else if ((npc.velocity.X < top_speed && npc.direction == 1) || (npc.velocity.X > -top_speed && npc.direction == -1)) // below top speed
{
npc.velocity.X += (float)npc.direction * acceleration; // accellerate fwd; can happen midair
if ((float)npc.direction * npc.velocity.X > top_speed)
npc.velocity.X = (float)npc.direction * top_speed; // but cap at top speed
}
} // END no fall/jump or wet or moving forward
#endregion
#region walk up half and single bricks
if (npc.velocity.Y >= 0f) // not rising
{
int move_dir = 0;
if (npc.velocity.X < 0f)
move_dir = -1;
if (npc.velocity.X > 0f)
move_dir = 1;
Vector2 next_pos = npc.position;
next_pos.X += npc.velocity.X;
int x_in_front = (int)((next_pos.X + (float)(npc.width / 2) + (float)((npc.width / 2 + 1) * move_dir)) / 16f);
int y_of_feet = (int)((next_pos.Y + (float)npc.height - 1f) / 16f);
if (Main.tile[x_in_front, y_of_feet] == null)
Main.tile[x_in_front, y_of_feet] = new Tile();
if (Main.tile[x_in_front, y_of_feet - 1] == null)
Main.tile[x_in_front, y_of_feet - 1] = new Tile();
if (Main.tile[x_in_front, y_of_feet - 2] == null)
Main.tile[x_in_front, y_of_feet - 2] = new Tile();
if (Main.tile[x_in_front, y_of_feet - 3] == null)
Main.tile[x_in_front, y_of_feet - 3] = new Tile();
if (Main.tile[x_in_front, y_of_feet + 1] == null)
Main.tile[x_in_front, y_of_feet + 1] = new Tile();
if ((float)(x_in_front * 16) < next_pos.X + (float)npc.width && (float)(x_in_front * 16 + 16) > next_pos.X && ((Main.tile[x_in_front, y_of_feet].nactive() && !Main.tile[x_in_front, y_of_feet].topSlope() && !Main.tile[x_in_front, y_of_feet - 1].topSlope() && TileDef.solid[(int)Main.tile[x_in_front, y_of_feet].type] && !TileDef.solidTop[(int)Main.tile[x_in_front, y_of_feet].type]) || (Main.tile[x_in_front, y_of_feet - 1].halfBrick() && Main.tile[x_in_front, y_of_feet - 1].nactive())) && (!Main.tile[x_in_front, y_of_feet - 1].nactive() || !TileDef.solid[(int)Main.tile[x_in_front, y_of_feet - 1].type] || TileDef.solidTop[(int)Main.tile[x_in_front, y_of_feet - 1].type] || (Main.tile[x_in_front, y_of_feet - 1].halfBrick() && (!Main.tile[x_in_front, y_of_feet - 4].nactive() || !TileDef.solid[(int)Main.tile[x_in_front, y_of_feet - 4].type] || TileDef.solidTop[(int)Main.tile[x_in_front, y_of_feet - 4].type]))) && (!Main.tile[x_in_front, y_of_feet - 2].nactive() || !TileDef.solid[(int)Main.tile[x_in_front, y_of_feet - 2].type] || TileDef.solidTop[(int)Main.tile[x_in_front, y_of_feet - 2].type]) && (!Main.tile[x_in_front, y_of_feet - 3].nactive() || !TileDef.solid[(int)Main.tile[x_in_front, y_of_feet - 3].type] || TileDef.solidTop[(int)Main.tile[x_in_front, y_of_feet - 3].type]) && (!Main.tile[x_in_front - move_dir, y_of_feet - 3].nactive() || !TileDef.solid[(int)Main.tile[x_in_front - move_dir, y_of_feet - 3].type]))
{ // if there's a brick to potentially climb up
float y_of_step = (float)(y_of_feet * 16);
if (Main.tile[x_in_front, y_of_feet].halfBrick())
y_of_step += 8f;
if (Main.tile[x_in_front, y_of_feet - 1].halfBrick())
y_of_step -= 8f;
if (y_of_step < next_pos.Y + (float)npc.height) // if step is above feet
{
float step_length = next_pos.Y + (float)npc.height - y_of_step;
if ((double)step_length <= 16.1) // close enough to make it up (can climb one block length)
{
npc.gfxOffY += npc.position.Y + (float)npc.height - y_of_step;
npc.position.Y = y_of_step - (float)npc.height; // climb onto step
if (step_length < 9f)
npc.stepSpeed = 1f;
else
npc.stepSpeed = 2f;
}
}
}
}
#endregion
#region new Tile()s, jumping
if (npc.velocity.Y == 0f && standing_on_solid_tile) // no fall/jump
{
int x_in_front = (int)((npc.position.X + (float)(npc.width / 2) + (float)((npc.width / 2 + 2) * npc.direction) + npc.velocity.X * 5f) / 16f);
int y_above_feet = (int)((npc.position.Y + (float)npc.height - 15f) / 16f); // 15 pix above feet
if (Main.tile[x_in_front, y_above_feet] == null)
Main.tile[x_in_front, y_above_feet] = new Tile();
if (Main.tile[x_in_front, y_above_feet - 1] == null)
Main.tile[x_in_front, y_above_feet - 1] = new Tile();
if (Main.tile[x_in_front, y_above_feet - 2] == null)
Main.tile[x_in_front, y_above_feet - 2] = new Tile();
if (Main.tile[x_in_front, y_above_feet - 3] == null)
Main.tile[x_in_front, y_above_feet - 3] = new Tile();
if (Main.tile[x_in_front, y_above_feet + 1] == null)
Main.tile[x_in_front, y_above_feet + 1] = new Tile();
if (Main.tile[x_in_front + npc.direction, y_above_feet - 1] == null)
Main.tile[x_in_front + npc.direction, y_above_feet - 1] = new Tile();
if (Main.tile[x_in_front + npc.direction, y_above_feet + 1] == null)
Main.tile[x_in_front + npc.direction, y_above_feet + 1] = new Tile();
if (Main.tile[x_in_front - npc.direction, y_above_feet + 1] == null)
Main.tile[x_in_front - npc.direction, y_above_feet + 1] = new Tile();
if (moving_forward)
{ // moving forward: various jumping
if (Main.tile[x_in_front, y_above_feet - 2].nactive() && TileDef.solid[(int)Main.tile[x_in_front, y_above_feet - 2].type])
{ // 3 blocks above ground level(head height) blocked
if (Main.tile[x_in_front, y_above_feet - 3].nactive() && TileDef.solid[(int)Main.tile[x_in_front, y_above_feet - 3].type])
{ // 4 blocks above ground level(over head) blocked
if (state == State.stalking) npc.velocity.Y = -8f;
else npc.velocity.Y = -8.5f; // jump with power 8.5 (for 4 block steps)
npc.netUpdate = true;
goto Jump_End;
}
if (state == State.stalking) npc.velocity.Y = -7f;
else npc.velocity.Y = -7.5f; // jump with power 7.5 (for 3 block steps)
npc.netUpdate = true;
goto Jump_End;
} // for everything else, head height clear:
else
{
if (Main.tile[x_in_front, y_above_feet - 1].nactive() && !Main.tile[x_in_front, y_above_feet - 1].topSlope() && TileDef.solid[(int)Main.tile[x_in_front, y_above_feet - 1].type])
{ // 2 blocks above ground level(mid body height) blocked
if (state == State.stalking) npc.velocity.Y = -6f;
else npc.velocity.Y = -7f; // jump with power 7 (for 2 block steps)
npc.netUpdate = true;
goto Jump_End;
}
if (npc.position.Y + (float)npc.height - (float)(y_above_feet * 16) > 20f && Main.tile[x_in_front, y_above_feet].nactive() && !Main.tile[x_in_front, y_above_feet].topSlope() && TileDef.solid[(int)Main.tile[x_in_front, y_above_feet].type])
{ // 1? block above ground level(foot height) blocked?
if (state == State.stalking) npc.velocity.Y = -5f;
else npc.velocity.Y = -6f; // jump with power 6 (for 1 block steps)
npc.netUpdate = true;
goto Jump_End;
}
if ((npc.directionY < 0 || Math.Abs(npc.velocity.X) > 3f) && (!Main.tile[x_in_front, y_above_feet + 2].nactive() || !TileDef.solid[(int)Main.tile[x_in_front, y_above_feet + 2].type]) && (!Main.tile[x_in_front + npc.direction, y_above_feet + 3].nactive() || !TileDef.solid[(int)Main.tile[x_in_front + npc.direction, y_above_feet + 3].type]))
{ // target is above & moving fast enough & no solid tile ahead to step on for 2 spaces in front
if (state == State.stalking) npc.velocity.Y = -7f;
else npc.velocity.Y = -8f; // jump with power 8 (to leap gaps)
npc.netUpdate = true;
goto Jump_End;
}
}
}
}
Jump_End: { }
#endregion
#region save state
if (state == State.stalking) npc.ai[1] = 0;
else if (state == State.pouncing) npc.ai[1] = 1;
else if (state == State.chasing) npc.ai[1] = 2;
else if (state == State.start_fleeing) npc.ai[1] = 3;
else if (state == State.fleeing) npc.ai[1] = 4;
#endregion
}
public override void DealtPlayer(Player player, int hitDir, int dmgDealt, bool crit)
{
npc.ai[3] = 0; // reset boredom when it hits a player.
}
public override void SelectFrame(int currentFrame)
{
const int frameCount = 33, textureHeight = 2048;
int sprite_height = textureHeight / frameCount;
if (npc.velocity.Y == 0f || npc.wet) // no jump/fall or wet
{
if (npc.velocity.X < -2f) npc.spriteDirection = -1;
else if (npc.velocity.X > 2f) npc.spriteDirection = 1;
else npc.spriteDirection = npc.direction;
}
if (npc.velocity.Y != 0f) // jump/fall
{
npc.frame.Y = sprite_height * 32 + 2; // frame 33=jump/fall
npc.frameCounter = 0.0;
}
else // no jump/fall
{
if (npc.velocity.X == 0f)
{
npc.frameCounter = 0.0;
npc.frame.Y = 0; // frame 1=standing still
}
else
{
if (Math.Abs(npc.velocity.X) < 3f) // slow
{
npc.frameCounter += (double)Math.Abs(npc.velocity.X);
while (npc.frameCounter >= 2.667) // 6.0)
{
npc.frameCounter -= 2.667; // 0.0;
npc.frame.Y = npc.frame.Y + sprite_height;
if (npc.frame.Y / sprite_height >= 19) // frame==20
{
npc.frame.Y = sprite_height; // reset to frame 2
}
if (npc.frame.Y / sprite_height <= 0) // frame 1
{
npc.frame.Y = sprite_height; // reset to frame 2
}
}
}
else // fast
{
npc.frameCounter += (double)Math.Abs(npc.velocity.X);
while (npc.frameCounter >= 4.615) // 10.0)
{
npc.frameCounter -= 4.615; // 0.0;
npc.frame.Y = npc.frame.Y + sprite_height;
if (npc.frame.Y / sprite_height >= 32) // frame==33
{
npc.frame.Y = sprite_height * 19; // reset to frame 20
}
if (npc.frame.Y / sprite_height <= 18) // slow frame
{
npc.frame.Y = sprite_height * 19; // reset to frame 20
}
}
}
}
} // END no jump/fall
}
}
}