public void Serialize() { var test = new MabiDictionary(); test.SetBool("a bool", true); test.SetByte("a byte", 1); test.SetShort("a short", 2); test.SetInt("an int", 3); test.SetFloat("a float", 4); test.SetString("a string", "five, special chars :;"); var test2 = test.ToString(); Assert.Equal("a bool:b:1;a byte:1:1;a short:2:2;an int:4:3;a float:f:4;a string:s:five, special chars %C%S;", test2); }
public void Serialize() { var test = new MabiDictionary(); test.SetBool("a bool", true); test.SetByte("a byte", 1); test.SetShort("a short", 2); test.SetInt("an int", 3); test.SetFloat("a float", 4); test.SetString("a string", "five, special chars :;"); var test2 = test.ToString(); Assert.Equal("a bool:b:1;a byte:1:1;a short:2:2;an int:4:3;a float:f:4;a string:s:five, special chars %C%S;", test2); }
public void GmcpBoost(ChannelClient client, Packet packet) { var multiplier = packet.GetFloat(); var creature = client.GetCreatureSafe(packet.Id); var speedBonus = (short)(multiplier * 100 - 100); speedBonus = (short)Math2.Clamp(0, 1000, speedBonus); if (speedBonus == 0) { creature.Conditions.Deactivate(ConditionsC.Hurry); } else { var extra = new MabiDictionary(); extra.SetShort("VAL", speedBonus); creature.Conditions.Activate(ConditionsC.Hurry, extra); } Send.ServerMessage(creature, Localization.Get("Speed boost: {0}x"), multiplier.ToString("0.0", CultureInfo.InvariantCulture)); }
/// <summary> /// Removes previous stat mods and adds new ones. /// </summary> /// <param name="data"></param> /// <param name="option"></param> private void SwitchStatMods(TitleData data, bool option) { // Remove prev stat mods if (option && _optionTitleData != null) { _creature.StatMods.Remove(StatModSource.Title, this.SelectedOptionTitle); if (_titleData.Effects.Any(a => a.Key == "Speed")) { _creature.Conditions.Deactivate(ConditionsC.Hurry); } } else if (!option && _titleData != null) { _creature.StatMods.Remove(StatModSource.Title, this.SelectedTitle); if (_titleData.Effects.Any(a => a.Key == "Speed")) { _creature.Conditions.Deactivate(ConditionsC.Hurry); } } // Add new stat mods if (data != null) { foreach (var effect in data.Effects) { // Simply adding the bonuses allows to "recover" stats by // using different titles, eg first +40, then +120, to // add 160 Life, even though it should only be 120? // Not much of a problem with title apply delay. switch (effect.Key) { case "Life": _creature.StatMods.Add(Stat.LifeMaxMod, effect.Value, StatModSource.Title, data.Id); if (effect.Value > 0) { _creature.Life += effect.Value; // Add value } else { _creature.Life = _creature.Life; // "Reset" stat (in case of reducation, stat = max) } break; case "Mana": _creature.StatMods.Add(Stat.ManaMaxMod, effect.Value, StatModSource.Title, data.Id); if (effect.Value > 0) { _creature.Mana += effect.Value; } else { _creature.Mana = _creature.Mana; } break; case "Stamina": // Adjust hunger to new max value, so Food stays // at the same percentage. var hungerRate = (100 / _creature.StaminaMax * _creature.Hunger) / 100f; _creature.StatMods.Add(Stat.StaminaMaxMod, effect.Value, StatModSource.Title, data.Id); if (effect.Value > 0) { _creature.Stamina += effect.Value; } else { _creature.Stamina = _creature.Stamina; } _creature.Hunger = _creature.StaminaMax * hungerRate; break; case "Str": _creature.StatMods.Add(Stat.StrMod, effect.Value, StatModSource.Title, data.Id); break; case "Int": _creature.StatMods.Add(Stat.IntMod, effect.Value, StatModSource.Title, data.Id); break; case "Dex": _creature.StatMods.Add(Stat.DexMod, effect.Value, StatModSource.Title, data.Id); break; case "Will": _creature.StatMods.Add(Stat.WillMod, effect.Value, StatModSource.Title, data.Id); break; case "Luck": _creature.StatMods.Add(Stat.LuckMod, effect.Value, StatModSource.Title, data.Id); break; case "Defense": _creature.StatMods.Add(Stat.DefenseBaseMod, effect.Value, StatModSource.Title, data.Id); break; case "Protection": _creature.StatMods.Add(Stat.ProtectionBaseMod, effect.Value, StatModSource.Title, data.Id); break; case "MinAttack": _creature.StatMods.Add(Stat.AttackMinMod, effect.Value, StatModSource.Title, data.Id); break; case "MaxAttack": _creature.StatMods.Add(Stat.AttackMaxMod, effect.Value, StatModSource.Title, data.Id); break; case "MinInjury": _creature.StatMods.Add(Stat.InjuryMinMod, effect.Value, StatModSource.Title, data.Id); break; case "MaxInjury": _creature.StatMods.Add(Stat.InjuryMaxMod, effect.Value, StatModSource.Title, data.Id); break; case "Crit": _creature.StatMods.Add(Stat.CriticalMod, effect.Value, StatModSource.Title, data.Id); break; case "CP": _creature.StatMods.Add(Stat.CombatPowerMod, effect.Value, StatModSource.Title, data.Id); break; case "MagicAttack": _creature.StatMods.Add(Stat.MagicAttackMod, effect.Value, StatModSource.Title, data.Id); break; case "MagicDefense": _creature.StatMods.Add(Stat.MagicDefenseMod, effect.Value, StatModSource.Title, data.Id); break; case "MagicProtection": _creature.StatMods.Add(Stat.MagicProtectionMod, effect.Value, StatModSource.Title, data.Id); break; case "Speed": // XXX: Conditions with idents to deactive them // more easily, like stat mods and regens? var extra = new MabiDictionary(); extra.SetShort("VAL", (short)effect.Value); _creature.Conditions.Activate(ConditionsC.Hurry, extra); break; default: Log.Warning("SwitchStatMods: Unknown title effect '{0}' in title {1}.", effect.Key, data.Id); break; } } } // Broadcast new stats if creature is in a region yet if (_creature.Region != Region.Limbo) { Send.StatUpdate(_creature, StatUpdateType.Private, Stat.LifeMaxMod, Stat.Life, Stat.LifeInjured, Stat.ManaMaxMod, Stat.Mana, Stat.StaminaMaxMod, Stat.Stamina, Stat.StrMod, Stat.IntMod, Stat.DexMod, Stat.WillMod, Stat.LuckMod, Stat.DefenseBaseMod, Stat.ProtectionBaseMod, Stat.AttackMinMod, Stat.AttackMaxMod, Stat.InjuryMinMod, Stat.InjuryMaxMod, Stat.CriticalMod, Stat.CombatPower, Stat.MagicAttackMod, Stat.MagicDefenseMod, Stat.MagicProtectionMod ); Send.StatUpdate(_creature, StatUpdateType.Public, Stat.Life, Stat.LifeMaxMod, Stat.LifeMax); } // Save data if (!option) { _titleData = data; } else { _optionTitleData = data; } }
/// <summary> /// Uses the skill /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void UseSkill(Creature attacker, Skill skill, long targetEntityId) { var target = attacker.Region.GetCreature(targetEntityId); var attackerPos = attacker.GetPosition(); var targetPos = target.GetPosition(); // Check target + collisions if (target == null || attacker.Region.Collisions.Any(attackerPos, targetPos)) { Send.SkillUseSilentCancel(attacker); return; } // Stop movement attacker.StopMove(); target.StopMove(); Send.SkillUseEntity(attacker, skill.Info.Id, targetEntityId); skill.State = SkillState.Used; // Counter if (Counterattack.Handle(target, attacker)) { return; } // Defense/Protection decrease on target var debuffChance = (int)skill.RankData.Var6; var defDecrease = (int)skill.RankData.Var3; var protDecrease = (int)skill.RankData.Var4; var extra = new MabiDictionary(); extra.SetShort("NEW_DEF", (short)defDecrease); extra.SetShort("NEW_PROT", (short)protDecrease); extra.SetLong("DDP_CHAR", attacker.EntityId); extra.SetShort("DDP_SKILL", (short)skill.Info.Id); var rnd = RandomProvider.Get(); if (rnd.NextDouble() * 100 < debuffChance) { Send.Effect(target, Effect.SpinningUppercutDebuff, (short)skill.Info.Id, 0, defDecrease, protDecrease); target.Conditions.Activate(ConditionsC.DefProtectDebuff, extra); attacker.Temp.SpinningUppercutDebuffApplied = true; } // Prepare Combat Actions var cap = new CombatActionPack(attacker, skill.Info.Id); var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, targetEntityId, skill.Info.Id); aAction.Set(AttackerOptions.Result); var tAction = new TargetAction(CombatActionType.TakeHit | CombatActionType.Attacker, target, attacker, skill.Info.Id); tAction.Set(TargetOptions.Result | TargetOptions.FighterUnk); cap.Add(aAction, tAction); // Damage var damage = (attacker.GetRndFighterDamage() * (skill.RankData.Var1 / 100f)); // Chain Mastery Damage Bonus var chainMasterySkill = attacker.Skills.Get(SkillId.ChainMastery); var damageBonus = (chainMasterySkill == null ? 0 : chainMasterySkill.RankData.Var1); damage += damage * (damageBonus / 100f); // Master Title - Damage +20% if (attacker.Titles.SelectedTitle == skill.Data.MasterTitle) { damage += (damage * 0.2f); } // Critical Hit var critChance = attacker.GetRightCritChance(target.Protection); CriticalHit.Handle(attacker, critChance, ref damage, tAction); // Handle skills and reductions SkillHelper.HandleDefenseProtection(target, ref damage); HeavyStander.Handle(attacker, target, ref damage, tAction); SkillHelper.HandleConditions(attacker, target, ref damage); ManaShield.Handle(target, ref damage, tAction); // Apply Damage target.TakeDamage(tAction.Damage = damage, attacker); // Aggro target.Aggro(attacker); // Stun Times tAction.Stun = TargetStun; aAction.Stun = AttackerStun; // Death and Knockback if (target.IsDead) { if (target.Is(RaceStands.KnockDownable)) { tAction.Set(TargetOptions.FinishingKnockDown); attacker.Shove(target, KnockbackDistance); } else { tAction.Set(TargetOptions.Finished | TargetOptions.FinishingHit); } } else { if (!target.IsKnockedDown) { target.Stability -= StabilityReduction; } if (target.IsUnstable && target.Is(RaceStands.KnockDownable)) { tAction.Set(TargetOptions.KnockDown); attacker.Shove(target, KnockbackDistance); } } cap.Handle(); // Chain Progress to Stage 3 attacker.Temp.FighterChainStartTime = DateTime.Now; attacker.Temp.FighterChainLevel = 3; }
/// <summary> /// Removes previous stat mods and adds new ones. /// </summary> /// <param name="data"></param> /// <param name="option"></param> private void SwitchStatMods(TitleData data, bool option) { // Remove prev stat mods if (option && _optionTitleData != null) { _creature.StatMods.Remove(StatModSource.Title, this.SelectedOptionTitle); if (_optionTitleData.Effects.Any(a => a.Key == "Speed")) _creature.Conditions.Deactivate(ConditionsC.Hurry); } else if (!option && _titleData != null) { _creature.StatMods.Remove(StatModSource.Title, this.SelectedTitle); if (_titleData.Effects.Any(a => a.Key == "Speed")) _creature.Conditions.Deactivate(ConditionsC.Hurry); } // Add new stat mods if (data != null) { foreach (var effect in data.Effects) { // Simply adding the bonuses allows to "recover" stats by // using different titles, eg first +40, then +120, to // add 160 Life, even though it should only be 120? // Not much of a problem with title apply delay. switch (effect.Key) { case "Life": _creature.StatMods.Add(Stat.LifeMaxMod, effect.Value, StatModSource.Title, data.Id); if (effect.Value > 0) _creature.Life += effect.Value; // Add value else _creature.Life = _creature.Life; // "Reset" stat (in case of reducation, stat = max) break; case "Mana": _creature.StatMods.Add(Stat.ManaMaxMod, effect.Value, StatModSource.Title, data.Id); if (effect.Value > 0) _creature.Mana += effect.Value; else _creature.Mana = _creature.Mana; break; case "Stamina": // Adjust hunger to new max value, so Food stays // at the same percentage. var hungerRate = (100 / _creature.StaminaMax * _creature.Hunger) / 100f; _creature.StatMods.Add(Stat.StaminaMaxMod, effect.Value, StatModSource.Title, data.Id); if (effect.Value > 0) _creature.Stamina += effect.Value; else _creature.Stamina = _creature.Stamina; _creature.Hunger = _creature.StaminaMax * hungerRate; break; case "Str": _creature.StatMods.Add(Stat.StrMod, effect.Value, StatModSource.Title, data.Id); break; case "Int": _creature.StatMods.Add(Stat.IntMod, effect.Value, StatModSource.Title, data.Id); break; case "Dex": _creature.StatMods.Add(Stat.DexMod, effect.Value, StatModSource.Title, data.Id); break; case "Will": _creature.StatMods.Add(Stat.WillMod, effect.Value, StatModSource.Title, data.Id); break; case "Luck": _creature.StatMods.Add(Stat.LuckMod, effect.Value, StatModSource.Title, data.Id); break; case "Defense": _creature.StatMods.Add(Stat.DefenseBaseMod, effect.Value, StatModSource.Title, data.Id); break; case "Protection": _creature.StatMods.Add(Stat.ProtectionBaseMod, effect.Value, StatModSource.Title, data.Id); break; case "MinAttack": _creature.StatMods.Add(Stat.AttackMinMod, effect.Value, StatModSource.Title, data.Id); break; case "MaxAttack": _creature.StatMods.Add(Stat.AttackMaxMod, effect.Value, StatModSource.Title, data.Id); break; case "MinInjury": _creature.StatMods.Add(Stat.InjuryMinMod, effect.Value, StatModSource.Title, data.Id); break; case "MaxInjury": _creature.StatMods.Add(Stat.InjuryMaxMod, effect.Value, StatModSource.Title, data.Id); break; case "Crit": _creature.StatMods.Add(Stat.CriticalMod, effect.Value, StatModSource.Title, data.Id); break; case "CP": _creature.StatMods.Add(Stat.CombatPowerMod, effect.Value, StatModSource.Title, data.Id); break; case "MagicAttack": _creature.StatMods.Add(Stat.MagicAttackMod, effect.Value, StatModSource.Title, data.Id); break; case "MagicDefense": _creature.StatMods.Add(Stat.MagicDefenseMod, effect.Value, StatModSource.Title, data.Id); break; case "MagicProtection": _creature.StatMods.Add(Stat.MagicProtectionMod, effect.Value, StatModSource.Title, data.Id); break; case "Speed": // XXX: Conditions with idents to deactive them // more easily, like stat mods and regens? var extra = new MabiDictionary(); extra.SetShort("VAL", (short)effect.Value); _creature.Conditions.Activate(ConditionsC.Hurry, extra); break; default: Log.Warning("SwitchStatMods: Unknown title effect '{0}' in title {1}.", effect.Key, data.Id); break; } } } // Broadcast new stats if creature is in a region yet if (_creature.Region != Region.Limbo) { Send.StatUpdate(_creature, StatUpdateType.Private, Stat.LifeMaxMod, Stat.Life, Stat.LifeInjured, Stat.ManaMaxMod, Stat.Mana, Stat.StaminaMaxMod, Stat.Stamina, Stat.StrMod, Stat.IntMod, Stat.DexMod, Stat.WillMod, Stat.LuckMod, Stat.DefenseBaseMod, Stat.ProtectionBaseMod, Stat.AttackMinMod, Stat.AttackMaxMod, Stat.InjuryMinMod, Stat.InjuryMaxMod, Stat.CriticalMod, Stat.CombatPower, Stat.MagicAttackMod, Stat.MagicDefenseMod, Stat.MagicProtectionMod ); Send.StatUpdate(_creature, StatUpdateType.Public, Stat.Life, Stat.LifeMaxMod, Stat.LifeMax); } // Save data if (!option) _titleData = data; else _optionTitleData = data; }