// ---------------------------------- /// <summary> /// Inflicts damage upon the character- if HP reaches 0, the character dies. Oh no! /// </summary> /// <param name="Attacker">The attacker</param> /// <param name="damage">The raw damage value to inflict</param> /// <param name="hit_direction">The direction in which this projectile was moving</param> /// <param name="type">The type of damage inflicted</param> /// <param name="projectile">Projectile sender</param> public void Damage( Character Attacker, int damage, Vector2 hit_velocity, Shared.Type type = Shared.Type.MUNDANE, Projectile projectile = null) { Health_Points -= damage; Set_Invulnerability(); Particles.Do_Bloodspurt(this, 5); // Only allows the entity to be knocked and interrupted if this attacker is strong enough // ----------------------------------- Interrupt(); Shared.SFX_Sounds["Hit"].Play(); // Determine Knockback // ----------------------------------- float knock_value = 0f; if (projectile != null) { knock_value = projectile.Knockback; } else { knock_value = Attacker.Knockback; } if (knock_value > 50) { knock_value = 50; } if (knock_value < 0) { knock_value = 0; } Vector2 knockback_velocity = Vector2.Zero; knockback_velocity.X = knock_value; if (hit_velocity.X < 0f) { knockback_velocity.X = -knock_value; } // Ensures that we don't rack up a swap of hits and break the sound barrier // ---------------------------------- if (!(Math.Abs(External_Velocity.X) >= Math.Abs(knockback_velocity.X))) { External_Velocity.X += knockback_velocity.X; } if (!(Math.Abs(External_Velocity.Y) >= Math.Abs(knockback_velocity.Y))) { External_Velocity.Y += knockback_velocity.Y; } }
// ---------------------------------- /// <summary> /// Try entity dead /// </summary> public void Try_Dead() { if (!dead) { Shared.SFX_Sounds["Overflow"].Play(); Particles.Do_Bloodspurt(this, 20, 5); Particles.Do_Effect( "Death", 3, Vector2.Zero, Vector2.Zero, false, this); if (this is Player) { Shared.Player.Respawner.Time = Shared.Player.Respawn_Delay; } } dead = true; }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Behavior Actions // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// <summary> /// Pursuit behavior - NPC chases target entity /// </summary> /// <returns>Returns true if able to chase target</returns> public bool Pursue() { // ------------------------------- // Reference timer for ease of acess Clock pursue_timer = Timers["Pursue"]; // ------------------------------- if (target != null && !target.Is_dead()) { // ------------------------------- // Save result of Sight & Range check bool Sight_And_Range_Check = Sight_And_Range(target); // ------------------------------- if (!Sight_And_Range_Check && pursue_timer.Primary_Decision == 1) { pursue_timer.Time = host.Persistence; } if (Sight_And_Range_Check || pursue_timer.Time > 0f) { // ------------------------------- if (pursue_timer.Secondary_Decision == 0) { // ------------------------------- Shared.SFX_Sounds["ALERT"].Play(); Particles.Do_Effect( "Alert", 1, new Vector2(0, -((host.Get_Bounds().Height) / 2 + Particles.Effects["Alert"].Dimensions.Y)), Vector2.Zero, true, host); // Ensures the alert emote only plays once per sighting pursue_timer.Secondary_Decision = 1; // ------------------------------- } // ------------------------------- if (Sight_And_Range_Check) { pursue_timer.Primary_Decision = 1; } else { pursue_timer.Primary_Decision = 0; } // x_offset has our pursuer try to run past their target instead of atop them. // ------------------------------- int x_offset = 1; if (host.Direction == Shared.Direction.LEFT) { x_offset = -1; } // ------------------------------- Vector2 target_dest = new Vector2 ( target.Grid_Position.X + x_offset, target.Grid_Position.Y ); if (host.Grid_Position == target_dest) { Turn_Around(); } if (host.Direction == Shared.Direction.RIGHT && host.Grid_Position.X > target.Grid_Position.X) { Turn_Around(); } else if (host.Direction == Shared.Direction.LEFT && host.Grid_Position.X < target.Grid_Position.X) { Turn_Around(); } Chase(target_dest, "run"); // ------------------------------- return(true); } else if (pursue_timer.Secondary_Decision == 1) { // ------------------------------- Shared.SFX_Sounds["CONFUSED"].Play(); Particles.Do_Effect( "Confused", 2, new Vector2(0, -((host.Get_Bounds().Height / 2) + Particles.Effects["Alert"].Dimensions.Y)), Vector2.Zero, true, host); // Ensures the confused emote only plays once per sighting pursue_timer.Secondary_Decision = 0; // ------------------------------- } } else // Target is null! They don't exist no more! Or never did! Set to defaults. { pursue_timer.Time = 0f; pursue_timer.Primary_Decision = 0; pursue_timer.Secondary_Decision = 0; } return(false); }
public override void Draw(GameTime gameTime) { if (Enabled) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // World Render Order // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Prepare dead character list List <Character> Dead_Characters = new List <Character>(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Update // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // World Parallax // -------------------------------- worldParallax.Update(gameTime); // Perform Combat Collision Checks // -------------------------------- CollisionManager.Projectile_Collisions(); CollisionManager.Character_Collision(); // Terrain // -------------------------------- foreach (KeyValuePair <string, Terrain> terrain in worldTerrain) { terrain.Value.Update(gameTime); if (terrain_changed) { terrain.Value.Terrain_Render(); } } if (has_background && worldBKGTerrain.Count() != 0) { foreach (KeyValuePair <string, Terrain> terrain in worldBKGTerrain) { terrain.Value.Update(gameTime); if (terrain_changed) { terrain.Value.Terrain_Render(); } } } // Reset terrain changed flag terrain_changed = false; // ---------------------- // Characters // -------------------------------- if (Shared.Active_World.loaded) { foreach (Character character in worldCharacters) { if (character.Is_dead() && !(character is Player)) { Dead_Characters.Add(character); character.Enabled = false; break; } character.Update(gameTime); } if (Dead_Characters.Count() != 0) { foreach (Character dead_character in Dead_Characters) { worldCharacters.Remove(dead_character); } } } // -------------------------------- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Draw // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BKG Terrain // -------------------------------- if (has_background && worldBKGTerrain.Count() != 0) { foreach (KeyValuePair <string, Terrain> terrain in worldBKGTerrain) { terrain.Value.Draw(gameTime); } } // Characters // -------------------------------- foreach (Character character in worldCharacters) { character.Draw(gameTime); } // Terrain // -------------------------------- foreach (KeyValuePair <string, Terrain> terrain in worldTerrain) { terrain.Value.Draw(gameTime); } if (Shared.Debug) { string key = Get_Grid_Key(Shared.Player.Grid_Position.X, Shared.Player.Grid_Position.Y + 1); if (WorldTerrain.ContainsKey(key)) { Shared.DebugWindow.Message += WorldTerrain[key].Name + "\n"; } else { Shared.DebugWindow.Message += "Air \n"; } Shared.DebugWindow.Draw(gameTime); Shared.DebugWindow.Message = ""; } // -------------------------------- // Effects // -------------------------------- Particles.Draw_Effects(gameTime); // -------------------------------- // Projectiles // -------------------------------- Particles.Draw_Projectiles(gameTime); // -------------------------------- // GUI // -------------------------------- foreach (GUI_Element element in Shared.GUI) { element.Draw(gameTime); } // -------------------------------- } }
// ---------------------------------- #endregion // ---------------------------------- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Draw & Update & Bounds // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ---------------------------------- #region Draw & Update & Bounds /// <summary> /// Updates animation, position, logic, etc. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> public override void Update(GameTime gameTime) { // -------------------------- // Disable entities that are not within the screen // Hooray for optimization. // -------------------------- // Leniance radius lets specific groupds of entities load from a // determined bounds outside the screen // -------------------------- Shared.Scene = Shared.Screen.Get_WorldSpace(); float leniance_range = 15 * Shared.Block_Dimension; if (Get_Bounds().Top > Shared.Scene.Bottom + leniance_range) { Enabled = false; } else if (Get_Bounds().Bottom < Shared.Scene.Top - leniance_range) { Enabled = false; } else if (Get_Bounds().Left > Shared.Scene.Right + leniance_range) { Enabled = false; } else if (Get_Bounds().Right < Shared.Scene.Left - leniance_range) { Enabled = false; } else { Enabled = true; } if (Get_Bounds().Top >= Shared.Active_World.Size.Y) { if (!dead) { Health_Points = 0; Particles.Do_Bloodspurt(this, 50, 4, true); } } if (Enabled && !dead) { // ------------------------------- // Cooldown Control // ------------------------------- if (Attack_Roster.Count() != 0) { foreach (KeyValuePair <string, Attack> attack in Attack_Roster) { if (attack.Value.Cooldown_timer > 0f) { float elapsed_time = (float)gameTime.ElapsedGameTime.TotalSeconds; attack.Value.Cooldown_timer -= elapsed_time; } else { attack.Value.Cooldown_timer = 0f; } } } // ------------------------------- // ------------------------------- // 0 Health = Dead Character. Derp if (Health_Points <= 0) { Try_Dead(); } // ------------------------------- Physics(gameTime); // Runs physics checks Invulnerablity(gameTime); // Runs invulnerability timer // Jitter Fix // ------------------------ Position.X = (float)Math.Round(Position.X); Position.Y = (float)Math.Round(Position.Y); // ------------------------ Grid_Position.X = (int)Math.Round((Position.X / Shared.Pixel_Scale) / Shared.Block_Dimension); Grid_Position.Y = (int)Math.Ceiling((Position.Y / Shared.Pixel_Scale) / Shared.Block_Dimension); // Ensures we will not run out of range of our animation list if (Animated) { Shared.EntityState temp_state = State; // -------------------------- // Make sure animation set exists if (!Animation_state.ContainsKey(State)) { // The animation does not exist. Default animation to idle // -------------------------- temp_state = Shared.EntityState.IDLE; if (!Animation_state.ContainsKey(temp_state)) { // Idle isn't set? This entity is bugged. Avoid it. // -------------------------- return; } } int max_index; // -------------------------- // Animation Frame Calculation max_index = Animation_state[temp_state].Frames.Count(); anim_delay++; if (anim_delay > Shared.FPS) { anim_delay = 0; anim_index++; if (anim_index >= max_index) { final_frame = true; if (Animation_state[temp_state].Loop) { anim_index = 0; } else { anim_index = Animation_state[temp_state].Frames.Count() - 1; } } else { final_frame = false; } } // -------------------------- // Complete Attacks if (Active_Attack != "none" && final_frame) { Try_Attack_Clear(); } } } }
// ---------------------------------- /// <summary> /// Handles the limitation & spawning of attack projectiles /// </summary> public void Handle_Attack_Projectiles() { if (Active_Attack != "none") { if (Attack_Roster[Active_Attack].Hit_Frame == Anim_index) { // Velocity needs some extra calculations. // ---------------------------------- Vector2 new_velocity = Attack_Roster[Active_Attack].Velocity; if (Attack_Roster[Active_Attack].Directional_Velocity != 0) { float directional_velocity = Attack_Roster[Active_Attack].Directional_Velocity; if (ATK_Direction == Shared.Direction.LEFT) { new_velocity = new Vector2(-directional_velocity, 0); } if (ATK_Direction == Shared.Direction.RIGHT) { new_velocity = new Vector2(directional_velocity, 0); } if (ATK_Direction == Shared.Direction.UP) { new_velocity = new Vector2(0, -directional_velocity); } if (ATK_Direction == Shared.Direction.DOWN) { new_velocity = new Vector2(0, directional_velocity); } } // --------------------- // Inherit velocity // --------------------- if (Attack_Roster[Active_Attack].Inherit_Velocity) { // ----------------------- // This ensures you won't get super crappy backwards shots if ((Velocity.X > 0f && new_velocity.X > 0f) || (Velocity.X < 0f && new_velocity.X < 0f)) { new_velocity.X += (Velocity.X); } else if (new_velocity.X == 0f) { new_velocity.X += Velocity.X; } // ----------------------- new_velocity.Y += (Velocity.Y / 2); } // --------------------- Particles.Do_Projectile ( Attack_Roster[Active_Attack].Effect_Name, Attack_Roster[Active_Attack].Lifespan, Attack_Roster[Active_Attack].Source_Offset, new_velocity, Attack_Roster[Active_Attack].Damage, Attack_Roster[Active_Attack].Knockback, Attack_Roster[Active_Attack].Damage_Team, Attack_Roster[Active_Attack].Damage_Type, Attack_Roster[Active_Attack].Hit_Frame, Attack_Roster[Active_Attack].Follow_Source, this ); // ---------------------------------- } } }
/// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // --------- Defaults ------------- spriteBatch = new SpriteBatch(GraphicsDevice); // --------- Store Globals ------------- Shared.Batch = spriteBatch; Shared.Main = this; // --------- Load Assets ------------- Shared.IMG_Interface = AssetLoader.LoadContent <Texture2D>(Content, "Images/Interface"); Shared.IMG_Items = AssetLoader.LoadContent <Texture2D>(Content, "Images/Items"); Shared.IMG_Sprites = AssetLoader.LoadContent <Texture2D>(Content, "Images/Sprites"); Shared.IMG_Worlds = AssetLoader.LoadContent <Texture2D>(Content, "Images/Worlds"); Shared.SFX_Sounds = AssetLoader.LoadContent <SoundEffect>(Content, "Audio/SFX"); Shared.AUDIO_Music = AssetLoader.LoadContent <Song>(Content, "Audio/Music"); // --------- Load & Generate Particles & Effects ------------- Shared.IMG_Animations = AssetLoader.LoadContent <Texture2D>(Content, "Images/Effects/Animations"); Shared.IMG_Emotes = AssetLoader.LoadContent <Texture2D>(Content, "Images/Effects/Emotes"); Shared.IMG_Projectiles = AssetLoader.LoadContent <Texture2D>(Content, "Images/Effects/Projectiles"); Particles.Generate_Effects(); // --------- Build Tilesheets ------------- Shared.IMG_Tiles = AssetLoader.LoadContent <Texture2D>(Content, "Images/Objects/Tiles"); Shared.Tileset = new Dictionary <string, Tileset>(); Terrain.Generate_Tiles(Shared.IMG_Tiles); // --------- Build Parallaxs -------- Shared.IMG_Parallax = AssetLoader.LoadContent <Texture2D>(Content, "Images/Parallax"); Shared.World_Parallax = new Dictionary <string, WorldParallax>(); WorldParallax.Create_WorldParallax(); // --------- Debug Data ------------- Shared.Pixel = new Texture2D(Shared.Main.GraphicsDevice, 1, 1, false, SurfaceFormat.Color); Shared.Pixel.SetData(new[] { Color.White }); SpriteFont font = Content.Load <SpriteFont>("Fonts/Pigsfont"); Shared.DebugWindow = new BasicText(font, new Vector2(0, 100), "Test", Color.Lime); // --------- Set Up Menu Animation ------------- MediaPlayer.Play(Shared.AUDIO_Music["Menu"]); MediaPlayer.IsRepeating = true; MediaPlayer.Volume = 1f; Menu_Animation.Add(Shared.IMG_Interface["MenuSceneF1"]); Menu_Animation.Add(Shared.IMG_Interface["MenuSceneF2"]); Menu_Animation.Add(Shared.IMG_Interface["MenuSceneF3"]); Menu_Animation.Add(Shared.IMG_Interface["MenuSceneF4"]); // --------- Scene Creation ------------- // Menu Display ------------------------- Title = Shared.IMG_Interface["TitleBar"]; Menu_Parallax = Shared.World_Parallax["Menu"]; // -------------------------------------- mainMenu = new MainMenu(); Shared.MainMenu = mainMenu; Components.Add(mainMenu); playScene = new PlayScene(); Components.Add(playScene); deadScene = new DeadScene(); Shared.DeadScene = deadScene; Components.Add(deadScene); controlScene = new ControlsScene(); Components.Add(controlScene); aboutScene = new AboutScene(); Components.Add(aboutScene); creditScene = new CreditScene(); Components.Add(creditScene); splashscreen = new Splashscreen(); Components.Add(splashscreen); HideAllScenes(); splashscreen.Show(); // ----------------------------------------- }