public void ProcessDarkKnightDarkForce(int maxHp) { var pSkill = Parent.Skills.Get((int)Skills.DARKKNIGHT_DARK_FORCE); if (pSkill != null) { var minAmount = pSkill.X_Effect * 0.01 * maxHp; // x is low end of range var maxAmount = pSkill.Y_Effect * 0.01 * maxHp; // y is high end of range //Parent.SendMessage($"Min: {minAmount} | Max: {maxAmount}"); var effect = new UserEffectPacket(UserEffect.SkillAffected) { nSkillID = pSkill.nSkillID, }; if (Parent.Stats.nHP > minAmount && Parent.Stats.nHP < maxAmount) // in range { if (!bDarkForce) { effect.bDarkForceActive = true; effect.BroadcastEffect(Parent); } } else // not in range { if (bDarkForce) { effect.bDarkForceActive = true; effect.BroadcastEffect(Parent); } } } }
private void DoDice(int nSkillID, byte nSLV) { Parent.Buffs.Remove(nSkillID); var newBuff = new BuffSkill(nSkillID, nSLV); newBuff.State = (byte)(Constants.Rand.Next(6) + 1); var effect = new UserEffectPacket(UserEffect.SkillAffectedSelect) { nSelect = (byte)newBuff.State, nSkillID = nSkillID, nSLV = nSLV }; effect.BroadcastEffect(Parent); if (newBuff.State <= 1) { return; } newBuff.GenerateDice(); Parent.Buffs.Add(newBuff); }
private void DoTimeleap(int nSkillID) { if (Parent.Party?.Count > 1) { Parent.Party.ForEachMemberInField(Parent.Field.dwUniqueId, c => execute(c)); } else { execute(Parent); } void execute(Character c) { var effect = new UserEffectPacket(UserEffect.SkillAffected) { nSkillID = nSkillID, }; effect.BroadcastEffect(c); foreach (var cd in new List <Cooldown>(c.Cooldowns)) { if (cd.nSkillID != (int)Skills.VIPER_TIME_LEAP) { Parent.Cooldowns.Remove(cd); } } } }
public void CheckDragonFury(int maxMp) // CWvsContext::CheckDragonFury { if (Parent.Skills.Get((int)Skills.EVAN_DRAGON_FURY) is SkillEntry pSkill) { var minAmount = pSkill.X_Effect * maxMp / 100; // x is low end of range var maxAmount = pSkill.Y_Effect * maxMp / 100; // y is high end of range var effect = new UserEffectPacket(UserEffect.SkillAffected) { nSkillID = pSkill.nSkillID, }; if (Parent.Stats.nMP > minAmount && Parent.Stats.nMP < maxAmount) // in range { if (nDragonFury == 0) { effect.bDragonFuryActive = true; effect.BroadcastEffect(Parent); nDragonFury = pSkill.Template.Damage(pSkill.nSLV); } } else // not in range { if (nDragonFury != 0) { effect.bDragonFuryActive = false; effect.BroadcastEffect(Parent); } } } }
public bool Update() { switch (nType) { case AffectedAreaType.UserSkill: foreach (var mob in Field.Mobs) { if (!rcArea.PointInRect(mob.Position.CurrentXY)) { continue; } mob.TryApplySkillDamageStatus (Field.Users[dwOwnerId], nSkillID, nSLV, 0); } break; case AffectedAreaType.BlessedMist: // TODO fix the recovery numbers, its incorrect rn { var rate = MasterManager.SkillTemplates[nSkillID].X(nSLV) * 0.01; foreach (var user in Field.Users) { if (!rcArea.PointInRect(user.Position.CurrentXY)) { continue; } user.Modify.Heal(0, (int)(user.BasicStats.nMMP * rate)); var effect = new UserEffectPacket(UserEffect.SkillAffected) { nSkillID = nSkillID, nSLV = nSLV, }; effect.BroadcastEffect(user); } } break; case AffectedAreaType.MobSkill: foreach (var user in Field.Users) { if (!rcArea.PointInRect(user.Position.CurrentXY)) { continue; } var toAdd = new Debuff(nSkillID, nSLV); toAdd.StatType = SecondaryStatFlag.Poison; toAdd.Generate(); user.Buffs.Remove(toAdd.nBuffID); user.Buffs.Add(toAdd); } break; } return(StartTime.MillisSinceStart() >= Duration); }
public void AddSkillBuff(int nSkillID, int nSLV, double durationMultiplier = 1.0, int nOption = 0) { if (nSkillID == (int)Skills.MECHANIC_SAFETY) { nOption = Parent.Stats.SecondaryStats.rBeholder; } if (GetOrDefault(nSkillID) is BuffSkill bs) { if (bs.nSLV < nSLV) { bs.nSLV = (byte)nSLV; } bs.State = nOption; UpdateBuffInfo(bs); } else { var newBuff = new BuffSkill(nSkillID, (byte)nSLV); if (newBuff.Template.Morph > 0) { newBuff.State = Parent.Stats.nGender; // haxed } newBuff.Generate(durationMultiplier); if (newBuff.StatType != SecondaryStatFlag.None_DONT_USE) // TODO phase this out { RemoveIf(b => b.StatType == newBuff.StatType); } if (newBuff.Template.HasAffected) { var effect = new UserEffectPacket(UserEffect.SkillAffected) { nSkillID = nSkillID, }; effect.BroadcastEffect(Parent); } newBuff.State = nOption; Add(newBuff); } }
private void SwallowMob(int dwSwallowMobId, byte nSLV) { if (Parent.Field.Mobs.Remove(dwSwallowMobId)) { var effect = new UserEffectPacket(UserEffect.SkillUse) { nSkillID = (int)Skills.WILDHUNTER_SWALLOW, nSLV = nSLV, }; effect.BroadcastEffect(Parent); Parent.Cooldowns.UpdateOrInsert((int)Skills.WILDHUNTER_SWALLOW, 30); } }
private void DoPartyHeal(int nSkillID, int nHP) // // BMS: 0x005D3295 { var nIntFactor = Parent.BasicStats.nINT * 0.8; var nIntModifier = nIntFactor + Constants.Rand.Next() % (Parent.BasicStats.nINT - nIntFactor); // TODO determine if we want to even bother with adding the MAD factor or just increase the int/luk factors //var nMad = sender.Buffs.Sum(buff => buff.Stat[SecondaryStatFlags.MAD] != null ? buff.Stat[SecondaryStatFlags.MAD].nValue : 0); //var nMadFactor = nMad + nMad; // addition faster than multiplication :kek: var nHeal = (nIntModifier * 1.5 + Parent.BasicStats.nLUK); // * 0.01; // nMadFactor * 0.01; var nMembersInMap = Parent.Party != null?Parent.Party.MembersInMap(Parent.Field.dwUniqueId) : 1; var nHealAmount = (int)(nHeal * (nMembersInMap * 0.3 + 1.0) * nHP * 0.01 / nMembersInMap); if (Parent.Party?.Count > 1) { var effect = new UserEffectPacket(UserEffect.SkillAffected) { nSkillID = nSkillID, }; var nExp = 0; Parent.Party.ForEachMemberInField(Parent.Field.dwUniqueId, member => { if (member.Stats.nHP > 0) { var nPrevHP = member.Stats.nHP; member.Modify.Heal(nHealAmount); if (member.dwId != Parent.dwId) { nExp += 20 * (member.Stats.nHP - nPrevHP) / (8 * member.Stats.nLevel + 190); effect.BroadcastEffect(member); } } }); if (nExp > 0) { Parent.Modify.GainExp(nExp); } } else { Parent.Modify.Heal(nHealAmount); } }
public void CompleteQuest() { var Parent = Script.Parent.Character; Quest.nState = QuestActType.QuestComplete; Quest.tCompleted = DateTime.Now; var effect = new UserEffectPacket(UserEffect.QuestComplete); effect.BroadcastEffect(Parent); Parent.SendPacket(CPacket.CQuestMan.QuestCompleted(Quest.nQuestID)); Parent.SendPacket(CPacket.CQuestMan .QuestRecordMessage(Quest)); Parent.SendPacket(CPacket.CQuestMan .UserQuestResult(QuestResultType.Success, Quest, Quest.Template.EndNPC)); }
/// <summary> /// Updates and sends a TemporaryStatSet packet to parent and remote client around parent /// This informs the client of changes to the buff without the overhead of removing the buff and re-adding it /// </summary> /// <param name="toUpdate"></param> public void UpdateBuffInfo(AbstractBuff toUpdate) { toUpdate.Stat.Clear(); toUpdate.Generate(); // no need to remove first cuz it will overwrite the previous value Parent.Stats.SecondaryStats.SetFromSecondaryStat(Parent, toUpdate.Stat); toUpdate.Stat.BroadcastSet(Parent); Parent.ValidateStat(); if (toUpdate is BuffSkill buff && buff.Template.HasAffected) { var effect = new UserEffectPacket(UserEffect.SkillAffected) { nSkillID = buff.nSkillID, }; effect.BroadcastEffect(Parent); } }
public static void Handle(int nSkillID, byte nSLV, Character c, CInPacket p) { var ldwTeslaCoilSummonedID = new int[2]; if (nSkillID == (int)Skills.MECHANIC_TESLA_COIL) { var nDistance = p.Decode1(); if (nDistance == 2) { ldwTeslaCoilSummonedID[0] = p.Decode4(); ldwTeslaCoilSummonedID[1] = p.Decode4(); } } var x = p.Decode2(); var y = p.Decode2(); var bLeft = p.Decode1() > 0; var unk = p.Decode1(); // FH? if (nSkillID == (int)Skills.WILDHUNTER_MINE_DUMMY_SUMMONED && !c.Buffs.Contains((int)Skills.WILDHUNTER_MINE)) { c.SendMessage("Unable to spawn mine when buff isn't activated."); return; } if (!c.Skills.Cast(nSkillID, bLeft, true)) { return; } var robotMastery = c.Skills.Get((int)Skills.MECHANIC_MASTERY); var durationMultiplier = (100 + (robotMastery?.X_Effect ?? 0)) * 0.01; var pSkill = c.Skills.Get(nSkillID, true); if (ldwTeslaCoilSummonedID[0] > 0) { if (!c.Field.Summons.Handle_TeslaCoil(c, nSLV, x, y, ldwTeslaCoilSummonedID)) { return; } } else { var summon = c.Field.Summons.CreateSummon(c, nSkillID, nSLV, x, y); switch (summon.nMoveAbility) { case SummonMoveAbility.CircleFollow: case SummonMoveAbility.Follow: c.Buffs.AddSkillBuff(nSkillID, pSkill.nSLV, durationMultiplier); break; } } var effect = new UserEffectPacket(UserEffect.SkillUse) { nSkillID = nSkillID, nSLV = pSkill.nSLV, }; effect.BroadcastEffect(c, false); switch ((Skills)nSkillID) { case Skills.MECHANIC_VELOCITY_CONTROLER: { foreach (var item in c.Field.Mobs) { item.TryApplySkillDamageStatus(c, nSkillID, pSkill.nSLV, 0); } c.Field.nVelocityControllerdwId = c.dwId; break; } case Skills.MECHANIC_AR_01: c.Skills.CastAffectedAreaSkill(nSkillID, nSLV, (short)pSkill.BuffTime, c.Position.CurrentXY, pSkill.Template.LT, pSkill.Template.RB); //if (c.Party?.Count > 1) //{ // c.Party.ApplyBuffToParty(c, c.Field.dwUniqueId, nSkillID, nSLV); //} //else //{ // c.Buffs.AddSkillBuff(nSkillID, pSkill.nSLV); //} break; } }
public void Stats(Action <StatModifier> action, bool bExclRequest = true) { var ctx = new StatModifier(Parent); action?.Invoke(ctx); if ((ctx.Flag & ModifyStatFlags.EXP) > 0) { if (ctx.EXP < 0) { ctx.EXP = 0; } var nExpSurplus = ctx.EXP - NextLevel.get_next_level_exp(ctx.Level - 1); // make sure this is before levelup func var levels = 0; var jobLevels = 0; int beforesp = ctx.SP; while (nExpSurplus >= 0) // while has more exp than required to reach next level { ctx.EXP = nExpSurplus; if (!ctx.try_process_levelup()) { break; } nExpSurplus = ctx.EXP - NextLevel.get_next_level_exp(ctx.Level - 1); levels += 1; Parent.NotifySocialChannels(SocialNotiflag.ChangeLevel); var job = ctx.Job; ctx.AutoJobAdvanceEvent(Parent); if (job != ctx.Job) { jobLevels += 1; } } if (levels > 0) { if (ctx.HP > 0) { ctx.HP = Parent.BasicStats.nMHP; ctx.MP = Parent.BasicStats.nMMP; } var effect = new UserEffectPacket(UserEffect.LevelUp); effect.BroadcastEffect(Parent); ctx.SP += (short)(jobLevels * 1); var aftersp = ctx.SP - beforesp; Parent.SendPacket(CPacket.IncSPMessage((byte)aftersp, ctx.Job)); // send sp gain message Parent.ValidateStat(); } } if ((ctx.Flag & ModifyStatFlags.Money) != 0) { ctx.Money = Math.Max(0, ctx.Money); } if ((ctx.Flag & ModifyStatFlags.POP) != 0) { ctx.POP = Math.Max((short)0, ctx.POP); } if ((ctx.Flag & ModifyStatFlags.Job) != 0) { Parent.Skills.SetMasterLevels(); var effect = new UserEffectPacket(UserEffect.JobChanged); effect.BroadcastEffect(Parent); if (JobLogic.IsEvan(ctx.Job)) { if (ctx.Job == 2200 && Parent.Dragon is null) { Parent.Dragon = new CDragon(Parent); Parent.Quests.OnCompleteQuest(null, 22100, 0, true); } Parent.Dragon.SpawnDragonToMap(); // update visuals } else { Parent.Modify.Skills(mod => { switch (ctx.Job) { // hacking aran skills together for now. TODO add a ForceVisible field or something to the skill class case 2100: mod.AddEntry(21000000, entry => entry.CurMastery = entry.MaxLevel); mod.AddEntry(21001003, entry => entry.CurMastery = entry.MaxLevel); break; case 2110: mod.AddEntry(21100000, entry => entry.CurMastery = entry.MaxLevel); mod.AddEntry(21100002, entry => entry.CurMastery = entry.MaxLevel); mod.AddEntry(21100004, entry => entry.CurMastery = entry.MaxLevel); mod.AddEntry(21100005, entry => entry.CurMastery = entry.MaxLevel); break; case 2111: mod.AddEntry(21110002, entry => entry.CurMastery = entry.MaxLevel); break; case 3300: mod.AddEntry(30001061, entry => entry.nSLV = 1); mod.AddEntry(30001062, entry => entry.nSLV = 1); break; case 3500: mod.AddEntry(30001068, entry => entry.nSLV = 1); break; } foreach (var skill in MasterManager.SkillTemplates.GetJobSkills(ctx.Job)) { var template = MasterManager.SkillTemplates[skill]; if (template.MasterLevel > 0) { mod.AddEntry(skill, entry => entry.CurMastery = (byte)template.MasterLevel); } } }); } // notify correct channels Parent.NotifySocialChannels(SocialNotiflag.ChangeJob); } if ((ctx.Flag & ModifyStatFlags.HP) > 0 || (ctx.Flag & ModifyStatFlags.MaxHP) > 0) { if (ctx.HP <= 0) // TODO move death exp loss (and safety charm) handling here { Parent.Field.Summons.RemoveCharSummons(Parent.dwId, SummonLeaveType.LEAVE_TYPE_USER_DEAD); } if (ctx.Job == 132) // dark knight { Parent.Skills.ProcessDarkKnightDarkForce(Parent.BasicStats.nMHP); } } if (((ctx.Flag & ModifyStatFlags.MP) > 0 || (ctx.Flag & ModifyStatFlags.MaxMP) > 0) && ctx.Job >= 2216 && ctx.Job <= 2218) // evan { Parent.Skills.CheckDragonFury(Parent.BasicStats.nMMP); } if ((ctx.Flag & ModifyStatFlags.BasicStat) != 0) { Parent.ValidateStat(); } if (ctx.Flag > 0) { Parent.SendPacket(CPacket.StatChanged(ctx, bExclRequest)); } }
public static void Handle_SummonedSkill(WvsGameClient c, CInPacket p) { var dwSummonedID = p.Decode4(); var item = c.Character.Field.Summons[dwSummonedID]; if (item is null) { return; } var nBuffSkillID = p.Decode4(); var pSkill = item.Parent.Skills.Get(nBuffSkillID, true); if (pSkill is null) { item.Parent.SendMessage($"Unable to find Skill ID {nBuffSkillID}."); return; } var nAction = p.Decode1(); var nIntervalMillis = SkillLogic.get_summoned_attack_delay(pSkill.nSkillID, pSkill.nSLV, (int)pSkill.X_Effect); #if DEBUG item.Parent.SendMessage("Skill ID sent from summon: " + nBuffSkillID); #endif if (!item.tLastBuffTime.AddedMillisExpired(nIntervalMillis)) { return; } item.tLastBuffTime = DateTime.Now; switch ((Skills)nBuffSkillID) { case Skills.MECHANIC_HEALING_ROBOT_H_LX: { if (item.Parent.Party != null) { item.Parent.Party.ApplyBuffToParty(item.Parent, item.Field.dwUniqueId, nBuffSkillID, pSkill.nSLV); } else if (item.Parent.Stats.nHP > 0) { var nHealAmount = (int)(item.Parent.BasicStats.nMHP * pSkill.Template.HP(pSkill.nSLV) * 0.01); item.Parent.Modify.Heal(nHealAmount); } } break; case Skills.DARKKNIGHT_BEHOLDERS_HEALING: { if (item.Parent.Stats.nHP > 0) { var nHealAmount = pSkill.Template.HP(pSkill.nSLV); item.Parent.Modify.Heal(nHealAmount); } } break; case Skills.DARKKNIGHT_BEHOLDERS_BUFF: { if (item.Parent.Stats.nHP > 0) { var nType = p.Decode1(); var buffid = 2022125 + Constants.Rand.Next(0, 5); if (!item.Parent.Buffs.Contains(-buffid)) { var buff = new BuffConsume(buffid); buff.GenerateBeholderBuff(item.Parent); item.Parent.Buffs.Add(buff); } } } break; case Skills.MECHANIC_ROBOROBO: { item.Field.Summons.CreateSummon(item.Parent, (int)Skills.MECHANIC_ROBOROBO_DUMMY, item.nSLV, item.Position.X, item.Position.Y); } break; default: item.Parent.SendMessage("Unhandled summon skill ID: " + nBuffSkillID); return; } var effect = new UserEffectPacket(UserEffect.SkillAffected) { nSkillID = nBuffSkillID, nSLV = pSkill.nSLV, }; effect.BroadcastEffect(item.Parent); // i think this includes parent item.Field.Broadcast(CPacket.CSummonedPool.SummonedSkill(item, item.nSkillID, nAction), item.Parent); // i think this excludes parent }