/// <summary> /// Called when the level is reset. Resets the player state and /// position. /// </summary> /// <param name="lev">Current level</param> public override void Reset(Level lev) { // Reset the base world object data base.Reset(lev); // Start with the walk cycle Animation.SetCycle(WalkCycle.StartCell, WalkCycle.EndCell, 0); curCycle = WalkCycle; prevState = AnimationState.Stop | AnimationState.Walk; // Reset player specific information Active = true; Collidable = true; shotStarted = false; shotTime = 0.0F; misfireValue = false; }
/// <summary> /// Update the player. /// </summary> /// <param name="gi">Input instance</param> /// <param name="lev">Current level</param> /// <returns>Always false</returns> public override bool Update(Input gi, Level lev) { // Assume there is no misfire this frame misfireValue = false; // If a shot is charging then update the time if (shotStarted) { shotTime += GameMain.SecondsPerFrame; } // If the player is not dead then update it if ((State & AnimationState.Dead) == 0) { // clear out the current direction but leave the animation // state State = prevState & AnimationState.AnimationMask; // If attacking then update the shot state if ((State & AnimationState.Attack) != 0) { // If the shot is not already fired and the current // animation cell is the one where the player shoots // then launch a shot if (!GetShotInfo()[0].Fired && Animation.CurCell == GetShotInfo()[0].ShootCell) { // Determine the direction of the shot WorldDir dir = WorldDir.Left; if ((DrawOptions & DrawOptions.BlitMirrorLeftRight) == 0) { dir = WorldDir.Right; } // Velocity multipliers float shotVelXMultiplier; float shotVelYMultiplier; // Determine the chance of a misfire based on the shot // bar charge (min to max) float misfireChance = shotMisfireMax - CurrentShotBarPercent * (shotMisfireMax - shotMisfireMin); if (GameMain.Random() < misfireChance) { // A misfire occurred so set the flag and // update the velocity multipliers accordingly misfireValue = true; shotVelXMultiplier = shotMisfireVelocityXMin + GameMain.Random() * (shotVelocityXMax - shotVelocityXMin); shotVelYMultiplier = shotMisfireVelocityYMin + GameMain.Random() * (shotVelocityYMax - shotVelocityYMin); } else { // No misfire, so the velocities are set // relative to the bar charge percentage shotVelXMultiplier = shotVelocityXMin + CurrentShotBarPercent * (shotVelocityXMax - shotVelocityXMin); shotVelYMultiplier = shotVelocityYMax - CurrentShotBarPercent * (shotVelocityYMax - shotVelocityYMin); } // Fire a shot and reset the charge time shotTime = 0.0F; FireShot(lev, GetShotInfo()[0], dir, shotVelXMultiplier, shotVelYMultiplier); } else if (Animation.Done) { // If the shot animation is done then reset shot info GetShotInfo()[0].Fired = false; State = AnimationState.Walk; curCycle = WalkCycle; } } else if (gi.KeyPressed((int)Keys.Down)) { // If pressing down then attempt to crawl. State = AnimationState.Duck; curCycle = DuckCycle; } else if (gi.KeyPressed((int)Keys.Up)) { // If pressing up then stand up State = AnimationState.Walk; curCycle = WalkCycle; } else if (!shotStarted && gi.KeyDown( (int)gi.HardwareKeys[buttonMapValue[ (int)Buttons.FireShot]])) { // If the fire button is pressed then start charging // the bar shotStarted = true; shotTime = 0.0F; } else if (shotStarted && gi.KeyReleased( (int)gi.HardwareKeys[buttonMapValue[ (int)Buttons.FireShot]])) { // If the fire button is released then start the shot // animation curCycle = AttackCycle; State |= AnimationState.Attack; Animation.SetCycle(WalkCycle.StartCell, WalkCycle.EndCell, WalkCycle.AnimationRate); Animation.StartOneShot(AttackCycle.StartCell, AttackCycle.EndCell, AttackCycle.AnimationRate); shotStarted = false; } Debug.Assert(curCycle != null, "Player.Update: Invalid animation sequence"); Debug.Assert((State & AnimationState.AnimationMask) != 0, "Player.Update: Invalid animation state determined"); // Attempt to walk in the direction the user is pressing if (gi.KeyDown((int)Keys.Left)) { WalkLeft(lev); } else if (gi.KeyDown((int)Keys.Right)) { WalkRight(lev); } else { Stop(lev); } Debug.Assert((State & AnimationState.DirectionMask) != 0 && (State & AnimationState.AnimationMask) != 0, "Player.Update: Invalid movement state determined"); } // Update the animation Animation.Update(GameMain.SecondsPerFrame); // Set the previous state prevState = State; // The player always returns false return(false); }
/// <summary> /// Initialize a world object with the data specified in the given /// DataRow. /// </summary> /// <param name="dr">DataRow defining the world object</param> /// <param name="lev">Current level</param> public WorldObject(DataRow dr, Level lev) { Debug.Assert(lev.AnimationList != null && lev.AnimationList.Count > 0, "WorldObject.WorldObject: No animations loaded"); Debug.Assert(lev.AIList != null && lev.AIList.Count > 0, "WorldObject.WorldObject: No AI loaded"); for (int i = 0; i < (int)AnimationType.Count; i++) { animationCycles[i] = new AnimationCycle(); Debug.Assert(animationCycles[i] != null, "WorldObject.WorldObject: Failed to allocate " + "animation cycle"); } // Walk WalkCycle.AnimationRate = int.Parse((string)dr["WalkAnimationRate"], CultureInfo.InvariantCulture); WalkCycle.StartCell = int.Parse((string)dr["WalkStartCell"], CultureInfo.InvariantCulture); WalkCycle.EndCell = int.Parse((string)dr["WalkEndCell"], CultureInfo.InvariantCulture); float x = float.Parse((string)dr["WalkBoundsX"], CultureInfo.InvariantCulture); float y = float.Parse((string)dr["WalkBoundsY"], CultureInfo.InvariantCulture); float r = float.Parse((string)dr["WalkBoundsRadius"], CultureInfo.InvariantCulture); WalkCycle.Bounds = new Bounds(x, y, r); // Attack AttackCycle.AnimationRate = int.Parse( (string)dr["AttackAnimationRate"], CultureInfo.InvariantCulture); AttackCycle.StartCell = int.Parse((string)dr["AttackStartCell"], CultureInfo.InvariantCulture); AttackCycle.EndCell = int.Parse((string)dr["AttackEndCell"], CultureInfo.InvariantCulture); x = float.Parse((string)dr["AttackBoundsX"], CultureInfo.InvariantCulture); y = float.Parse((string)dr["AttackBoundsY"], CultureInfo.InvariantCulture); r = float.Parse((string)dr["AttackBoundsRadius"], CultureInfo.InvariantCulture); AttackCycle.Bounds = new Bounds(x, y, r); // Duck DuckCycle.AnimationRate = int.Parse( (string)dr["DuckAnimationRate"], CultureInfo.InvariantCulture); DuckCycle.StartCell = int.Parse((string)dr["DuckStartCell"], CultureInfo.InvariantCulture); DuckCycle.EndCell = int.Parse((string)dr["DuckEndCell"], CultureInfo.InvariantCulture); x = float.Parse((string)dr["DuckBoundsX"], CultureInfo.InvariantCulture); y = float.Parse((string)dr["DuckBoundsY"], CultureInfo.InvariantCulture); r = float.Parse((string)dr["DuckBoundsRadius"], CultureInfo.InvariantCulture); DuckCycle.Bounds = new Bounds(x, y, r); // Death DeathCycle.AnimationRate = int.Parse( (string)dr["DeathAnimationRate"], CultureInfo.InvariantCulture); DeathCycle.StartCell = int.Parse((string)dr["DeathStartCell"], CultureInfo.InvariantCulture); DeathCycle.EndCell = int.Parse((string)dr["DeathEndCell"], CultureInfo.InvariantCulture); // General info worldXValue = float.Parse((string)dr["X"], CultureInfo.InvariantCulture); worldYValue = float.Parse((string)dr["Y"], CultureInfo.InvariantCulture); activateDistance = float.Parse((string)dr["ActivateDistance"], CultureInfo.InvariantCulture); collidableValue = bool.Parse((string)dr["Collidable"]); // Animation int animationId = int.Parse((string)dr["AnimationId"], CultureInfo.InvariantCulture); Debug.Assert(animationId >= 0 && animationId < lev.AnimationList.Count, "WorldObject.WorldObject: Animatin ID out of range"); animationValue = new Animation( (Animation)lev.AnimationList[animationId], 0, 0); Debug.Assert(animationValue != null && animationValue.Init, "WorldObject.WorldObject: Failed to initialize animation"); // AI int aiId = int.Parse((string)dr["AIId"], CultureInfo.InvariantCulture); if (aiId >= 0) { Debug.Assert(aiId < lev.AIList.Count, "WorldObject.WorldObject: AI Id out of range"); AILogic = AIHandler.Create((AI)lev.AIList[aiId]); AILogic.Init(this, lev); } // Draw options if (bool.Parse((string)dr["Transparency"])) { DrawOptions = DrawOptions.BlitKeyedTransparency; } // Shot, if one exists int numShots = 0; if (!dr.IsNull("Shot2AnimationId")) { numShots = 2; } else if (!dr.IsNull("Shot1AnimationId")) { numShots = 1; } if (numShots > 0) { shotInfoValue = new ShotInfo[numShots]; for (int i = 0; i < shotInfoValue.Length; i++) { shotInfoValue[i] = new ShotInfo(dr, i + 1); ShotInfo shot = shotInfoValue[i]; Debug.Assert(shot != null, "WorldObject.WorldObject: Failed to allocate " + "shot info"); } } ResetCollidable = collidableValue; ResetWorldX = worldXValue; ResetWorldY = worldYValue; }
/// <summary> /// Create an instance of the player. /// </summary> /// <param name="ds">DataSet defining the player</param> /// <param name="graphics">Graphics instance</param> /// <param name="animList">List of level animations</param> public Player(DataSet ds, IGraphics graphics, ArrayList animationList) { // Yes, this world object is the player Player = true; // The player is always active and collidable Active = true; Collidable = true; // Allocate space fore all animation cycles for (int i = 0; i < (int)AnimationType.Count; i++) { SetAnimationCycle(i, new AnimationCycle()); Debug.Assert(GetAnimationCycle(i) != null, "Player.Player: Failed to allocate animation cycle"); } // Start location DataTable dt = ds.Tables["StartLocation"]; Debug.Assert(dt != null && dt.Rows != null, "Player.Player: Invalid start location data"); WorldX = float.Parse((string)(dt.Rows[0]["X"]), CultureInfo.InvariantCulture); WorldY = float.Parse((string)(dt.Rows[0]["Y"]), CultureInfo.InvariantCulture); // Walk animation dt = ds.Tables["Walk"]; Debug.Assert(dt != null && dt.Rows != null && dt.Rows[0] != null, "Player.Player: Walk animation data not valid"); WalkCycle.AnimationRate = int.Parse((string)( dt.Rows[0]["NormalAnimationRate"]), CultureInfo.InvariantCulture); WalkCycle.ForceAnimationRate = int.Parse( (string)(dt.Rows[0]["ForceAnimationRate"]), CultureInfo.InvariantCulture); WalkCycle.MoveRate = float.Parse( (string)(dt.Rows[0]["MovementRate"]), CultureInfo.InvariantCulture); WalkCycle.StartCell = int.Parse( (string)(dt.Rows[0]["StartCell"]), CultureInfo.InvariantCulture); WalkCycle.EndCell = int.Parse((string)(dt.Rows[0]["EndCell"]), CultureInfo.InvariantCulture); WalkCycle.Bounds = new Bounds(dt.Rows[0]); // Attack animation dt = ds.Tables["Attack"]; Debug.Assert(dt != null && dt.Rows != null && dt.Rows[0] != null, "Player.Player: Attack animation data not valid"); AttackCycle.AnimationRate = int.Parse( (string)(dt.Rows[0]["NormalAnimationRate"]), CultureInfo.InvariantCulture); AttackCycle.ForceAnimationRate = int.Parse( (string)(dt.Rows[0]["ForceAnimationRate"]), CultureInfo.InvariantCulture); AttackCycle.MoveRate = float.Parse( (string)(dt.Rows[0]["MovementRate"]), CultureInfo.InvariantCulture); AttackCycle.StartCell = int.Parse( (string)(dt.Rows[0]["StartCell"]), CultureInfo.InvariantCulture); AttackCycle.EndCell = int.Parse( (string)(dt.Rows[0]["EndCell"]), CultureInfo.InvariantCulture); AttackCycle.Bounds = new Bounds(dt.Rows[0]); // Crawl animation dt = ds.Tables["Crawl"]; Debug.Assert(dt != null && dt.Rows != null && dt.Rows[0] != null, "Player.Player: Attack animation data not valid"); DuckCycle.AnimationRate = int.Parse( (string)(dt.Rows[0]["NormalAnimationRate"]), CultureInfo.InvariantCulture); DuckCycle.ForceAnimationRate = int.Parse( (string)(dt.Rows[0]["ForceAnimationRate"]), CultureInfo.InvariantCulture); DuckCycle.MoveRate = float.Parse( (string)(dt.Rows[0]["MovementRate"]), CultureInfo.InvariantCulture); DuckCycle.StartCell = int.Parse( (string)(dt.Rows[0]["StartCell"]), CultureInfo.InvariantCulture); DuckCycle.EndCell = int.Parse( (string)(dt.Rows[0]["EndCell"]), CultureInfo.InvariantCulture); DuckCycle.Bounds = new Bounds(dt.Rows[0]); // Death animation dt = ds.Tables["Death"]; Debug.Assert(dt != null && dt.Rows != null && dt.Rows[0] != null, "Player.Player: Death animation data not valid"); DeathCycle.AnimationRate = int.Parse( (string)(dt.Rows[0]["AnimationRate"]), CultureInfo.InvariantCulture); DeathCycle.StartCell = int.Parse( (string)(dt.Rows[0]["StartCell"]), CultureInfo.InvariantCulture); DeathCycle.EndCell = int.Parse((string)(dt.Rows[0]["EndCell"]), CultureInfo.InvariantCulture); // Shot dt = ds.Tables["Shot"]; Debug.Assert(dt != null && dt.Rows != null && dt.Rows[0] != null, "Player.Player: Shot info data not valid"); ShotInfo[] tempShotInfo = new ShotInfo[1]; tempShotInfo[0] = new ShotInfo(dt.Rows[0]); SetShotInfo(tempShotInfo); Debug.Assert(GetShotInfo() != null, "Player.Player: Failed to allocate shot info"); // General dt = ds.Tables["General"]; Debug.Assert(dt != null && dt.Rows != null && dt.Rows[0] != null, "Player.Player: General info data not valid"); DataRow dr = dt.Rows[0]; shotChargeTime = float.Parse((string)(dr["ShotChargeTime"]), CultureInfo.InvariantCulture); shotMisfireMin = float.Parse( (string)(dr["ShotMisfireMin"]), CultureInfo.InvariantCulture) / 100.0F; shotMisfireMax = float.Parse( (string)(dr["ShotMisfireMax"]), CultureInfo.InvariantCulture) / 100.0F; shotVelocityXMin = float.Parse( (string)(dr["ShotVelocityXMin"]), CultureInfo.InvariantCulture) / 100.0F; shotVelocityXMax = float.Parse( (string)(dr["ShotVelocityXMax"]), CultureInfo.InvariantCulture) / 100.0F; shotVelocityYMin = float.Parse( (string)(dr["ShotVelocityYMin"]), CultureInfo.InvariantCulture) / 100.0F; shotVelocityYMax = float.Parse( (string)(dr["ShotVelocityYMax"]), CultureInfo.InvariantCulture) / 100.0F; shotMisfireVelocityXMin = float.Parse( (string)(dr["ShotMisfireVelocityXMin"]), CultureInfo.InvariantCulture) / 100.0F; shotMisfireVelocityXMax = float.Parse( (string)(dr["ShotMisfireVelocityXMax"]), CultureInfo.InvariantCulture) / 100.0F; shotMisfireVelocityYMin = float.Parse( (string)(dr["ShotMisfireVelocityYMin"]), CultureInfo.InvariantCulture) / 100.0F; shotMisfireVelocityYMax = float.Parse( (string)(dr["ShotMisfireVelocityYMax"]), CultureInfo.InvariantCulture) / 100.0F; audioDeathId = int.Parse((string)(dr["DeathAudioId"]), CultureInfo.InvariantCulture); // Animation int animationId = int.Parse((string)(dr["AnimationId"]), CultureInfo.InvariantCulture); Debug.Assert(animationId >= 0 && animationId < animationList.Count, "Player.Player: Animation ID out of range"); Animation = new Animation((Animation)animationList[animationId], 0, 0); Debug.Assert(Animation != null && Animation.Init, "Player.Player: Failed to load animationation"); // Start with the walk cycle Animation.SetCycle(WalkCycle.StartCell, WalkCycle.EndCell, 0); curCycle = WalkCycle; // Check if drawing requires transparency if (bool.Parse((string)(dt.Rows[0]["Transparency"]))) { DrawOptions = DrawOptions.BlitKeyedTransparency; } ResetCollidable = Collidable; ResetWorldX = WorldX; ResetWorldY = WorldY; }
/// <summary> /// Sets one of the animation cycles available to a world object /// </summary> /// <param name="index">The index of the animation cycle</param> /// <param name="cycle">The animation cycle to store</param> protected void SetAnimationCycle(int index, AnimationCycle cycle) { animationCycles[index] = cycle; }