/// <summary> /// <para>Sends a <see cref="ModPacket"/> with <see cref="OriPlayer"/> data.</para> /// <inheritdoc cref="ModPacket.Send(int, int)"/> /// </summary> /// <param name="toWho">Who to send to. <see langword="255"/> for server, <see langword="-1"/> for all players.</param> /// <param name="fromWho">Sender, client to ignore.</param> internal void SendOriState(int toWho, int fromWho) { ModPacket packet = GetPacket(fromWho); OriPlayer fromPlayer = Main.player[fromWho].GetModPlayer <OriPlayer>(); BitsByte flags = new BitsByte { [0] = fromPlayer.IsOri, [1] = fromPlayer.Transforming, [2] = fromPlayer.UnrestrictedMovement, [3] = fromPlayer.SeinMinionActive, [4] = fromPlayer.multiplayerPlayerLight, }; packet.Write(flags); if (fromPlayer.Transforming) { packet.Write((ushort)fromPlayer.transformTimer); } if (fromPlayer.SeinMinionActive) { packet.Write((byte)fromPlayer.SeinMinionType); } packet.WriteRGB(fromPlayer.SpriteColorPrimary); packet.WriteRGBA(fromPlayer.SpriteColorSecondary); fromPlayer.input.WritePacket(packet); packet.Send(toWho, fromWho); }
/// <summary> /// Increases the level of <paramref name="player"/>'s <see cref="Ability"/> this Item represents to by 1. /// <para>By increasing by 1, the player can level it multiple times if they skip one, rather than having their level skip.</para> /// </summary> /// <param name="player">The player using the item.</param> /// <returns><see langword="true"/> if the ability can be leveled. If this returns <see langword="false"/>, this <see cref="AbilityMedallionBase"/> or the <see cref="Ability"/> must be fixed.</returns> public override bool UseItem(Player player) { OriPlayer oPlayer = player.GetModPlayer <OriPlayer>(); Ability ability = oPlayer.abilities[Id]; if (ability is ILevelable levelable) { levelable.Level++; if (player.whoAmI == Main.myPlayer) { string key = $"Mods.OriMod.Lore.{ability.GetType().Name}.{levelable.Level}"; if (Language.Exists(key)) { Main.NewText(Language.GetText(key), Color.LightCyan); } } string strStart = player.whoAmI == Main.myPlayer ? "You" : $"{player.name} has"; Main.NewText( levelable.Level == 1 ? $"{strStart} unlocked {NiceName(ability)}!" : $"{strStart} upgraded {NiceName(ability)} to Level {levelable.Level}!", Color.LightGreen); return(true); } Main.NewText($"OriMod dev bug: Ability {ability.GetType().Name} cannot be leveled.", Color.Red); return(false); }
public override bool NewRightClick(int i, int j) { OriPlayer oPlayer = OriPlayer.Local; Player player = oPlayer.player; Main.mouseRightRelease = false; if (oPlayer.Transforming) { return(false); } if (!oPlayer.IsOri) { oPlayer.BeginTransformation(); if (!oPlayer.HasTransformedOnce) { oPlayer.PlaySound("AbilityPedestal/abilityPedestalMusic", 0.25f); } } else { oPlayer.IsOri = false; oPlayer.PlaySound("SavePoints/checkpointSpawnSound"); Vector2 pos = player.position; pos.Y += 4; pos.X -= 2; for (int m = 0; m < 100; m++) { Dust dust = Dust.NewDustDirect(pos, 30, 30, DustID.Clentaminator_Cyan, 0f, 0f, 0, new Color(255, 255, 255)); dust.shader = GameShaders.Armor.GetSecondaryShader(19, Main.LocalPlayer); } } return(true); }
/// <summary> /// Returns <see langword="true"/> if the player does not have the <see cref="Ability"/> this Item represents upgraded to the <see cref="Ability.Level"/> this Item upgrades to. /// </summary> /// <param name="player">The <see cref="Player"/> using the item.</param> /// <returns><see langword="true"/> if the player does not have the <see cref="Ability"/> at this <see cref="Level"/>; otherwise, <see langword="false"/>.</returns> public override bool CanUseItem(Player player) { // Can only use the item if the ability to be unlocked has not been unlocked OriPlayer oPlayer = player.GetModPlayer <OriPlayer>(); return(oPlayer.abilities[Id].Level < Level); }
internal override void HandlePacket(BinaryReader reader, int fromWho) { OriPlayer fromPlayer = Main.player[fromWho].GetModPlayer <OriPlayer>(); BitsByte flags = reader.ReadByte(); bool oriSet = flags[0]; bool transforming = flags[1]; bool unrestrictedMovement = flags[2]; bool seinMinionActive = flags[3]; bool mpcPlayerLight = flags[4]; ushort transformTimer = transforming ? reader.ReadUInt16() : (ushort)0; byte seinMinionType = seinMinionActive ? reader.ReadByte() : (byte)0; Color spriteColorPrimary = reader.ReadRGB(); Color spriteColorSecondary = reader.ReadRGBA(); fromPlayer.IsOri = oriSet; fromPlayer.Transforming = transforming; fromPlayer.UnrestrictedMovement = unrestrictedMovement; fromPlayer.transformTimer = transformTimer; fromPlayer.SeinMinionType = seinMinionType; fromPlayer.SeinMinionActive = seinMinionActive; fromPlayer.multiplayerPlayerLight = mpcPlayerLight; fromPlayer.SpriteColorPrimary = spriteColorPrimary; fromPlayer.SpriteColorSecondary = spriteColorSecondary; fromPlayer.input.ReadPacket(reader); if (Main.netMode == NetmodeID.Server) { SendOriState(-1, fromWho); } }
public override void Action(CommandCaller caller, string input, string[] args) { OriPlayer oPlayer = caller.Player.GetModPlayer <OriPlayer>(); oPlayer.debugMode ^= true; Main.NewText("Toggled debug mode to " + oPlayer.debugMode); }
private static void BurrowEffects(int i, int j, ref Color drawColor, OriPlayer oPlayer) { Color orig = drawColor; Vector2 playerPos = Main.LocalPlayer.Center / 16; float dist = Vector2.Distance(playerPos, new Vector2(i, j)) - InnerRange; dist = Utils.Clamp((OuterRange - dist) / OuterRange, 0, 1); drawColor = Color.Lerp(orig, Color.White, (oPlayer.abilities.burrow.CanBurrow(Main.tile[i, j]) ? 0.8f : 0.4f) * dist); drawColor.A = orig.A; }
/// <summary> /// <para>Sends a <see cref="ModPacket"/> with ability data.</para> /// <inheritdoc cref="ModPacket.Send(int, int)"/> /// </summary> /// <param name="toWho">Who to send to. <see langword="255"/> for server, <see langword="-1"/> for all players.</param> /// <param name="fromWho">Sender, client to ignore.</param> /// <param name="changes">List of <see cref="AbilityId"/>s for abilities that have changed.</param> internal void SendAbilityState(int toWho, int fromWho, List <byte> changes) { ModPacket packet = GetPacket(fromWho); OriPlayer fromPlayer = Main.player[fromWho].GetModPlayer <OriPlayer>(); packet.Write((byte)changes.Count); foreach (byte id in changes) { packet.Write(id); fromPlayer.abilities[id].PreWritePacket(packet); } packet.Send(toWho, fromWho); }
public override bool Shoot(Player player, ref Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack) { OriPlayer oPlayer = player.GetModPlayer <OriPlayer>(); oPlayer.RemoveSeinBuffs(); player.AddBuff(item.buffType, 2); oPlayer.SeinMinionType = item.shoot; oPlayer.SeinMinionActive = true; if (player.altFunctionUse == 2) { player.MinionNPCTargetAim(); } oPlayer.SeinMinionId = Projectile.NewProjectile(player.Center, -Vector2.UnitY, item.shoot, item.damage, item.knockBack, player.whoAmI); return(false); }
internal static Vector2 GetMouseDirection(OriPlayer oPlayer, out float angle, Vector2?direction = null, float maxAngle = (float)Math.PI) { Player player = oPlayer.player; Vector2 dir = direction ?? new Vector2(player.direction, player.gravDir); Vector2 offset = Main.MouseWorld; offset = (offset - player.Center) * dir + player.Center; angle = Utils.Clamp(player.AngleTo(offset), -maxAngle, maxAngle); Vector2 result = Vector2.UnitX.RotatedBy(angle); result *= dir; return(result); }
internal override void HandlePacket(BinaryReader reader, int fromWho) { OriPlayer fromPlayer = Main.player[fromWho].GetModPlayer <OriPlayer>(); int len = reader.ReadByte(); var changes = new List <byte>(); for (int m = 0; m < len; m++) { byte id = reader.ReadByte(); changes.Add(id); fromPlayer.abilities[id].PreReadPacket(reader); } if (Main.netMode == NetmodeID.Server) { SendAbilityState(-1, fromWho, changes); } }
public override bool UseItem(Player player) { OriPlayer oPlayer = player.GetModPlayer <OriPlayer>(); oPlayer.IsOri ^= true; Vector2 pos = player.position; pos.Y += 4; pos.X -= 2; for (int m = 0; m < 100; m++) { Dust dust = Dust.NewDustDirect(pos, 30, 30, DustID.Clentaminator_Cyan, 0f, 0f, 0, new Color(255, 255, 255)); dust.shader = GameShaders.Armor.GetSecondaryShader(19, Main.LocalPlayer); } oPlayer.PlaySound("SavePoints/checkpointSpawnSound"); Item.NewItem(player.getRect(), ModContent.ItemType <OriPotionEmpty>(), noGrabDelay: true); return(true); }
internal AbilityManager(OriPlayer oPlayer) { this.oPlayer = oPlayer; //soulLink = new SoulLink(this); wallJump = new WallJump(this); stomp = new Stomp(this); airJump = new AirJump(this); bash = new Bash(this); glide = new Glide(this); climb = new Climb(this); chargeJump = new ChargeJump(this); wallChargeJump = new WallChargeJump(this); dash = new Dash(this); chargeDash = new ChargeDash(this); lookUp = new LookUp(this); crouch = new Crouch(this); burrow = new Burrow(this); launch = new Launch(this); }
public override void DrawEffects(int i, int j, int type, SpriteBatch spriteBatch, ref Color drawColor, ref int nextSpecialDrawIndex) { OriPlayer oPlayer = OriPlayer.Local; if (!oPlayer.abilities.burrow) { return; } BurrowEffects(i, j, ref drawColor, oPlayer); if (!oPlayer.debugMode) { return; } Point pos = new Point(i, j); if (Burrow.InnerHitbox.Points.Contains(pos)) { drawColor = Color.Red; } else if (Burrow.EnterHitbox.Points.Contains(pos)) { drawColor = Color.LimeGreen; } }
private static Ability AbilityFromObject(string str, OriPlayer oPlayer) { if (int.TryParse(str, out int id)) { if (id >= 0 && id <= AbilityId.Count) { return(oPlayer.abilities[id]); } Main.NewText($"\"{id}\" does not map to a valid AbilityID.", Color.Red); return(null); } string testName = str.ToLower(); foreach (Ability ab in oPlayer.abilities) { if (ab.GetType().Name.ToLower() == testName) { return(ab); } } Main.NewText($"\"{str}\" is not a valid Ability.", Color.Red); return(null); }
/// <summary> /// Updates the player animation by one frame, and changes it depending on various conditions. /// </summary> public override void Update() { OriPlayer oPlayer = player.GetModPlayer <OriPlayer>(); AbilityManager abilities = oPlayer.abilities; // Transformation if (oPlayer.Transforming) { PlayTrack("Transform", speed: oPlayer.HasTransformedOnce?OriPlayer.RepeatedTransformRate: 1); return; } if (!oPlayer.IsOri) { return; } // Handle some "special" movement // Todo, consider dedicated sprites to these actions, i.e. mounted, pulley, grapple if (player.pulley || player.mount.Active) { PlayTrack("Idle"); return; } if (oPlayer.IsGrappling) { if (Math.Abs(player.velocity.X) > 0.1f) { PlayTrack("Jump", frameIndex: 1); return; } PlayTrack(oPlayer.OnWall ? "IdleAgainst" : "Default"); return; } // Abilities // Start with simple cases if (abilities.bash) { PlayTrack("Bash"); return; } if (abilities.chargeJump.Active) { PlayTrack("ChargeJump"); return; } if (abilities.wallJump) { PlayTrack("WallJump"); return; } if (abilities.airJump) { PlayTrack("AirJump", rotation: FrameTime * 0.6f *player.gravDir *player.direction); return; } if (abilities.burrow) { float rad = (float)Math.Atan2(abilities.burrow.velocity.X, -abilities.burrow.velocity.Y * player.gravDir); PlayTrack("Burrow", rotation: rad *player.gravDir); return; } if (abilities.dash || abilities.chargeDash) { PlayTrack("Dash", frameIndex: Math.Abs(player.velocity.X) < 12f ? 1 : 0); return; } if (abilities.wallChargeJump) { PlayTrack("Dash", frameIndex: 0, rotation: abilities.wallChargeJump.Angle *player.gravDir *abilities.wallChargeJump.XDirection); return; } // Switch-case for animations with start/mid/end segments if (abilities.glide) { switch (abilities.glide.AbilityState) { case Ability.State.Starting: PlayTrack("GlideStart"); return; case Ability.State.Active: PlayTrack("Glide"); return; case Ability.State.Ending: PlayTrack("GlideStart", direction: Direction.Reverse); return; } } if (abilities.crouch) { switch (abilities.crouch.AbilityState) { case Ability.State.Starting: PlayTrack("CrouchStart"); return; case Ability.State.Active: PlayTrack("Crouch"); return; case Ability.State.Ending: PlayTrack("CrouchStart", direction: Direction.Reverse); return; } } if (abilities.lookUp) { switch (abilities.lookUp.AbilityState) { case Ability.State.Starting: PlayTrack("LookUpStart"); return; case Ability.State.Active: PlayTrack("LookUp"); return; case Ability.State.Ending: PlayTrack("LookUpStart", direction: Direction.Reverse); return; } } // More complex animations if (abilities.stomp) { switch (abilities.stomp.AbilityState) { case Ability.State.Starting: PlayTrack("AirJump", rotation: FrameTime * 0.8f); return; case Ability.State.Active: PlayTrack("ChargeJump", duration: 2, rotation: (float)Math.PI, loop: LoopMode.Always, direction: Direction.PingPong); return; } } if (abilities.launch) { if (abilities.launch.Active) { // Launch angle needs to be offset by 90 degrees since it uses Stomp animation // Disable spriteeffects as launching should not be flipped PlayTrack("ChargeJump", duration: 6, rotation: abilities.launch.LaunchAngle + (float)Math.PI / 2 * player.gravDir, loop: LoopMode.Always, direction: Direction.PingPong, effects: SpriteEffects.None); } else { int ct = abilities.launch.CurrentTime; float accel = ct * (ct < 5 ? 0.05f : ct < 20 ? 0.03f : 0.02f); // Somewhat accelerating speed of rotation PlayTrack("AirJump", rotation: SpriteRotation + accel * player.direction); } return; } if (abilities.climb) { if (abilities.climb.Ending) { PlayTrack("Jump", frameIndex: 0); return; } if (!abilities.climb.IsCharging) { if (Math.Abs(player.velocity.Y) < 0.1f) { PlayTrack("ClimbIdle"); } else { PlayTrack(player.velocity.Y * player.gravDir < 0 ? "Climb" : "WallSlide", speed: Math.Abs(player.velocity.Y) * 0.4f); } return; } if (!abilities.wallChargeJump.Charged) { PlayTrack("WallChargeJumpCharge", frameIndex: abilities.wallChargeJump.Refreshed?null: (int?)0); return; } // Aim angle determines frame of sprite. // 0 is middle (pointing straight left/right), 1-2 pointing downward, 3-4 pointing upward int frame = 0; float angle = abilities.wallChargeJump.Angle; if (angle < -0.46f) { frame = 2; } else if (angle < -0.17f) { frame = 1; } else if (angle > 0.46f) { frame = 4; } else if (angle > 0.17f) { frame = 3; } PlayTrack("WallChargeJumpAim", frameIndex: frame); return; } // Generic/misc movement if (oPlayer.OnWall && !oPlayer.IsGrounded) { PlayTrack("WallSlide"); return; } if (!oPlayer.IsGrounded) { // Probably the best way to check for jumping vs falling PlayTrack(player.velocity.Y * player.gravDir < 0 ? "Jump" : "Falling"); return; } if (Math.Abs(player.velocity.X) > 0.2f) { // Movement deadzone recommended for running animations // Else subtle movements such as sandstorm can cause a running animation // Animation speed is also determined by player speed, as it should be PlayTrack("Running", speed: (int)Math.Abs(player.velocity.X) * 0.45f); return; } PlayTrack(oPlayer.OnWall ? "IdleAgainst" : "Idle"); }
public override void Action(CommandCaller caller, string input, string[] args) { OriPlayer oPlayer = caller.Player.GetModPlayer <OriPlayer>(); if (!oPlayer.debugMode) { Main.NewText("This command cannot be used outside of debug mode.", Color.Red); return; } if (args.Length < 1) { Main.NewText($"This command requires arguments. Usage: {Usage}", Color.Red); return; } switch (args[0]) { case "unlockall": oPlayer.abilities.UnlockAllAbilities(); Main.NewText("Unlocked all abilities.", Color.LightGreen); return; case "resetall": oPlayer.abilities.ResetAllAbilities(); Main.NewText("Reset all abilities.", Color.LightGreen); return; } Ability ability = AbilityFromObject(args[0], oPlayer); string abilityName = ability.GetType().Name; if (ability is ILevelable levelable) { if (args.Length < 2) { Main.NewText($"{abilityName}'s Level is {levelable.Level}.", Color.LightGreen); } else if (byte.TryParse(args[1], out byte level)) { levelable.Level = level; if (level <= levelable.MaxLevel) { Main.NewText($"{abilityName}'s Level has been set to {level}.", Color.LightGreen); } else { Main.NewText($"{abilityName}'s Level has been set to {level}. Note that {abilityName}'s max level is {levelable.MaxLevel}, so this ability's behavior may be unexpected or unbalanced.", Color.GreenYellow); } } else { Main.NewText($"\"{args[1]}\" is not a valid input for level.", Color.Red); } } else { if (args.Length < 2) { Main.NewText($"{abilityName}'s fixed Level is {ability.Level}.", Color.LightGreen); } else { Main.NewText($"{abilityName} cannot have its level modified. {FailedAbilityReason(ability)}", Color.Red); } } }
public override bool CanUseItem(Player player) { OriPlayer oPlayer = player.GetModPlayer <OriPlayer>(); return(player.altFunctionUse != 2 && (!oPlayer.SeinMinionActive || oPlayer.SeinMinionType != item.shoot)); }