private static bool LoadAttribute(int powerSNO, GameAttributeMap attributes, int attributeId, out float result) { GameAttribute attr = GameAttribute.Attributes[attributeId]; bool needs_key = _powerKeyedAttributes.Contains(attributeId); if (attr is GameAttributeF) { if (needs_key) { result = attributes[(GameAttributeF)attr, powerSNO]; } else { result = attributes[(GameAttributeF)attr]; } return(true); } else if (attr is GameAttributeI) { if (needs_key) { result = (float)attributes[(GameAttributeI)attr, powerSNO]; } else { result = (float)attributes[(GameAttributeI)attr]; } return(true); } else if (attr is GameAttributeB) { if (needs_key) { result = attributes[(GameAttributeB)attr, powerSNO] ? 1 : 0; } else { result = attributes[(GameAttributeB)attr] ? 1 : 0; } return(true); } else { Logger.Error("invalid attribute {0}", attributeId); result = 0; return(false); } }
private static bool LoadIdentifier(int powerSNO, TagKeyScript scriptTag, GameAttributeMap attributes, Random rand, int numb1, int numb2, int numb3, int numb4, out float result) { switch (numb1) { case 0: return(LoadAttribute(powerSNO, attributes, numb2, out result)); case 1: // slevel result = attributes[GameAttribute.Skill, powerSNO]; return(true); case 22: // absolute power formula ref return(Evaluate(numb2, new TagKeyScript(numb3), attributes, rand, out result)); default: if (numb1 >= 23 && numb1 <= 62) // SF_N, relative power formula ref { int SF_N = numb1 - 23; TagKeyScript relativeTag = PowerTagHelper.GenerateTagForScriptFormula(SF_N); return(Evaluate(powerSNO, relativeTag, attributes, rand, out result)); } else if (numb1 >= 63 && numb1 <= 72) // known gamebalance power table id range { result = BinaryIntToFloat(numb1); // simply store id, used later by Table() return(true); } else { Logger.Error("unknown identifier"); result = 0; return(false); } } }
// FIXME: Hardcoded hell. /komiga public void Die(Player player) { /*var killAni = new int[]{ 0x2cd7, 0x2cd4, 0x01b378, 0x2cdc, 0x02f2, 0x2ccf, 0x2cd0, 0x2cd1, 0x2cd2, 0x2cd3, 0x2cd5, 0x01b144, 0x2cd6, 0x2cd8, 0x2cda, 0x2cd9 };*/ this.World.BroadcastIfRevealed(new PlayEffectMessage() { ActorId = this.DynamicID, Effect = Effect.Hit, OptionalParameter = 0x2, }, this); this.World.BroadcastIfRevealed(new PlayEffectMessage() { ActorId = this.DynamicID, Effect = Effect.Unknown12, }, this); this.World.BroadcastIfRevealed(new PlayHitEffectMessage() { ActorID = this.DynamicID, HitDealer = player.DynamicID, Field2 = 0x2, Field3 = false, }, this); this.World.BroadcastIfRevealed(new FloatingNumberMessage() { ActorID = this.DynamicID, Number = 9001.0f, Type = FloatingNumberMessage.FloatType.White, }, this); this.World.BroadcastIfRevealed(new ANNDataMessage(Opcodes.ANNDataMessage13) { ActorID = this.DynamicID }, this); player.UpdateExp(this.Attributes[GameAttribute.Experience_Granted]); player.ExpBonusData.Update(player.GBHandle.Type, this.GBHandle.Type); this.World.BroadcastIfRevealed(new PlayAnimationMessage() { ActorID = this.DynamicID, Field1 = 0xb, Field2 = 0, tAnim = new PlayAnimationMessageSpec[1] { new PlayAnimationMessageSpec() { Field0 = 0x2, Field1 = AnimationSet.GetRandomDeath(),//killAni[RandomHelper.Next(killAni.Length)], Field2 = 0x0, Field3 = 1f } } }, this); this.World.BroadcastIfRevealed(new ANNDataMessage(Opcodes.ANNDataMessage24) { ActorID = this.DynamicID, }, this); GameAttributeMap attribs = new GameAttributeMap(); attribs[GameAttribute.Hitpoints_Cur] = 0f; attribs[GameAttribute.Could_Have_Ragdolled] = true; attribs[GameAttribute.Deleted_On_Server] = true; foreach (var msg in attribs.GetMessageList(this.DynamicID)) this.World.BroadcastIfRevealed(msg, this); this.World.SpawnRandomItemDrop(player, this.Position); this.World.SpawnGold(player, this.Position); if (RandomHelper.Next(1, 100) < 20) this.World.SpawnHealthGlobe(player, this.Position); this.PlayLore(); this.Destroy(); }
public void UpdateExp(int addedExp) { GameAttributeMap attribs = new GameAttributeMap(); this.Attributes[GameAttribute.Experience_Next] -= addedExp; // Levelup if ((this.Attributes[GameAttribute.Experience_Next] <= 0) && (this.Attributes[GameAttribute.Level] < this.Attributes[GameAttribute.Level_Cap])) { this.Attributes[GameAttribute.Level]++; this.Properties.LevelUp(); if (this.Attributes[GameAttribute.Level] < this.Attributes[GameAttribute.Level_Cap]) { this.Attributes[GameAttribute.Experience_Next] = this.Attributes[GameAttribute.Experience_Next] + LevelBorders[this.Attributes[GameAttribute.Level]]; } else { this.Attributes[GameAttribute.Experience_Next] = 0; } // Notes on attribute increment algorithm: // Precision: Barbarian => +1, else => +2 // Defense: Wizard or Demon Hunter => (lvl+1)%2+1, else => +2 // Vitality: Wizard or Demon Hunter => lvl%2+1, Barbarian => +2, else +1 // Attack: All +2 // Attack this.Attributes[GameAttribute.Attack] += 2f; // Precision if (this.Properties.Class == ToonClass.Barbarian) { this.Attributes[GameAttribute.Precision] += 1f; } else { this.Attributes[GameAttribute.Precision] += 2f; } // Vitality and Defense if ((this.Properties.Class == ToonClass.Wizard) || (this.Properties.Class == ToonClass.DemonHunter)) { this.Attributes[GameAttribute.Vitality] += (this.Attributes[GameAttribute.Level] % 2) + 1f; this.Attributes[GameAttribute.Defense] += ((this.Attributes[GameAttribute.Level] + 1) % 2) + 1f; } else if (this.Properties.Class == ToonClass.Barbarian) { this.Attributes[GameAttribute.Vitality] += 2f; this.Attributes[GameAttribute.Defense] += 2f; } else { this.Attributes[GameAttribute.Vitality] += 1f; this.Attributes[GameAttribute.Defense] += 2f; } attribs[GameAttribute.Level] = this.Attributes[GameAttribute.Level]; attribs[GameAttribute.Defense] = this.Attributes[GameAttribute.Defense]; attribs[GameAttribute.Vitality] = this.Attributes[GameAttribute.Vitality]; attribs[GameAttribute.Precision] = this.Attributes[GameAttribute.Precision]; attribs[GameAttribute.Attack] = this.Attributes[GameAttribute.Attack]; attribs[GameAttribute.Experience_Next] = this.Attributes[GameAttribute.Experience_Next]; attribs.SendMessage(this.InGameClient, this.DynamicID); this.InGameClient.SendMessage(new PlayerLevel() { Id = 0x98, Field0 = 0x00000000, Field1 = this.Attributes[GameAttribute.Level], }); this.InGameClient.SendMessage(new PlayEffectMessage() { Id = 0x7a, ActorID = this.DynamicID, Field1 = 6, }); /*this.InGameClient.SendMessage(new PlayEffectMessage() { Id = 0x7a, ActorID = this.DynamicID, Field1 = 32, Field2 = LevelUpEffects[this.Attributes[GameAttribute.Level]], });*/ this.World.BroadcastGlobal(new PlayEffectMessage() { Id = 0x7a, ActorID = this.DynamicID, Field1 = 32, Field2 = LevelUpEffects[this.Attributes[GameAttribute.Level]], }); } // constant 0 exp at Level_Cap if (this.Attributes[GameAttribute.Experience_Next] < 0) { this.Attributes[GameAttribute.Experience_Next] = 0; } attribs[GameAttribute.Experience_Next] = this.Attributes[GameAttribute.Experience_Next]; attribs.SendMessage(this.InGameClient, this.DynamicID); //this.Attributes.SendMessage(this.InGameClient, this.DynamicID); kills the player atm }
// FIXME: Hardcoded crap public override void OnEnter(World world) { this.World.Reveal(this); // FIXME: hackedy hack var attribs = new GameAttributeMap(); attribs[GameAttribute.Hitpoints_Healed_Target] = 76f; attribs.SendMessage(InGameClient, this.DynamicID); }
public static bool Evaluate(int powerSNO, TagKeyScript scriptTag, GameAttributeMap attributes, Random rand, out float result) { result = 0; ScriptFormula scriptFormula = FindScriptFormula(powerSNO, scriptTag); if (scriptFormula == null) { //Logger.Error("could not find script tag {0} in power {1}", scriptTag.ID, powerSNO); return(false); } byte[] script = scriptFormula.OpCodeArray; Stack <float> stack = new Stack <float>(4); // analysis of all stack formulas found the biggest stack is currently 11 int pos = 0; float numb1, numb2, numb3; float temp; while (pos < script.Length) { switch (script[pos]) { case 0: // return if (StackUnderflow(stack, 1)) { return(false); } result = stack.Pop(); return(true); case 1: // function pos += 4; switch (script[pos]) { case 0: // Min() if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(Math.Min(numb1, numb2)); break; case 1: // Max() if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(Math.Max(numb1, numb2)); break; case 2: // Pin() if (StackUnderflow(stack, 3)) { return(false); } numb3 = stack.Pop(); numb2 = stack.Pop(); numb1 = stack.Pop(); if (numb2 > numb1) { stack.Push(numb2); } else if (numb1 > numb3) { stack.Push(numb3); } else { stack.Push(numb1); } break; case 3: // RandomIntMinRange() if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(rand.Next((int)numb1, (int)numb1 + (int)numb2)); break; case 4: // RandomIntMinMax() if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(rand.Next((int)numb1, (int)numb2)); break; case 5: // Floor() if (StackUnderflow(stack, 1)) { return(false); } numb1 = stack.Pop(); stack.Push((float)Math.Floor(numb1)); break; case 9: // RandomFloatMinRange() if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 + (float)rand.NextDouble() * numb2); break; case 10: // RandomFloatMinMax() if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 + (float)rand.NextDouble() * (numb2 - numb1)); break; case 11: // Table() if (StackUnderflow(stack, 2)) { return(false); } float index = stack.Pop(); float tableID = stack.Pop(); if (!LookupBalanceTable(tableID, index, out temp)) { return(false); } stack.Push(temp); break; default: Logger.Error("Unimplemented function"); return(false); } break; case 5: // external identifier if (!LoadIdentifier(powerSNO, scriptTag, attributes, rand, BitConverter.ToInt32(script, pos + 4 * 1), BitConverter.ToInt32(script, pos + 4 * 2), BitConverter.ToInt32(script, pos + 4 * 3), BitConverter.ToInt32(script, pos + 4 * 4), out temp)) { return(false); } stack.Push(temp); pos += 4 * 4; break; case 6: // push float pos += 4; stack.Push(BitConverter.ToSingle(script, pos)); break; case 8: // operator > if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 > numb2 ? 1 : 0); break; case 11: // operator + if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 + numb2); break; case 12: // operator - if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 - numb2); break; case 13: // operator * if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 * numb2); break; case 14: // operator / if (StackUnderflow(stack, 2)) { return(false); } numb2 = stack.Pop(); numb1 = stack.Pop(); if (numb2 == 0f) { Logger.Error("Division by zero, 0 pushed to stack instead of divide result"); stack.Push(0f); } else { stack.Push(numb1 / numb2); } break; case 16: // operator -(unary) if (StackUnderflow(stack, 1)) { return(false); } numb1 = stack.Pop(); stack.Push(-numb1); break; case 17: // operator ?: if (StackUnderflow(stack, 3)) { return(false); } numb3 = stack.Pop(); numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 != 0 ? numb2 : numb3); break; default: Logger.Error("Unimplemented OpCode({0})", script[pos]); return(false); } pos += 4; } // HACK: ignore bad formula if (powerSNO == Skills.Skills.Barbarian.FurySpenders.Whirlwind && scriptTag.ID == 266560) // ScriptFormula(4) { return(true); } Logger.Error("script finished without return opcode"); return(false); }
// FIXME: Hardcoded hell. /komiga public void Die(Player player) { /*var killAni = new int[]{ * 0x2cd7, * 0x2cd4, * 0x01b378, * 0x2cdc, * 0x02f2, * 0x2ccf, * 0x2cd0, * 0x2cd1, * 0x2cd2, * 0x2cd3, * 0x2cd5, * 0x01b144, * 0x2cd6, * 0x2cd8, * 0x2cda, * 0x2cd9 * };*/ this.World.BroadcastIfRevealed(new PlayEffectMessage() { ActorId = this.DynamicID, Effect = Effect.Hit, OptionalParameter = 0x2, }, this); this.World.BroadcastIfRevealed(new PlayEffectMessage() { ActorId = this.DynamicID, Effect = Effect.Unknown12, }, this); this.World.BroadcastIfRevealed(new PlayHitEffectMessage() { ActorID = this.DynamicID, HitDealer = player.DynamicID, Field2 = 0x2, Field3 = false, }, this); this.World.BroadcastIfRevealed(new FloatingNumberMessage() { ActorID = this.DynamicID, Number = 9001.0f, Type = FloatingNumberMessage.FloatType.White, }, this); this.World.BroadcastIfRevealed(new ANNDataMessage(Opcodes.ANNDataMessage13) { ActorID = this.DynamicID }, this); this.World.BroadcastIfRevealed(new PlayAnimationMessage() { ActorID = this.DynamicID, Field1 = 0xb, Field2 = 0, tAnim = new PlayAnimationMessageSpec[1] { new PlayAnimationMessageSpec() { Field0 = 0x2, Field1 = AnimationSet.GetRandomDeath(),//killAni[RandomHelper.Next(killAni.Length)], Field2 = 0x0, Field3 = 1f } } }, this); this.World.BroadcastIfRevealed(new ANNDataMessage(Opcodes.ANNDataMessage24) { ActorID = this.DynamicID, }, this); GameAttributeMap attribs = this.Attributes; //TODO change it /fasbat attribs[GameAttribute.Hitpoints_Cur] = 0f; attribs[GameAttribute.Could_Have_Ragdolled] = true; attribs[GameAttribute.Deleted_On_Server] = true; attribs.BroadcastChangedIfRevealed(); // Spawn Random item and give exp for each player in range List <Player> players = this.GetPlayersInRange(26f); foreach (Player plr in players) { plr.UpdateExp(this.Attributes[GameAttribute.Experience_Granted]); this.World.SpawnRandomItemDrop(this, plr); } player.ExpBonusData.Update(player.GBHandle.Type, this.GBHandle.Type); this.World.SpawnGold(this, player); if (RandomHelper.Next(1, 100) < 20) { this.World.SpawnHealthGlobe(this, player, this.Position); } this.PlayLore(); this.Destroy(); }
// FIXME: Hardcoded crap public override void OnEnter(World world) { this.World.Reveal(this); // This "tick" stuff is somehow required to use these values.. /komiga this.InGameClient.SendMessage(new DWordDataMessage() // TICK { Id = 0x0089, Field0 = 0x00000077, }); this.InGameClient.FlushOutgoingBuffer(); // FIXME: hackedy hack var attribs = new GameAttributeMap(); attribs[GameAttribute.Hitpoints_Healed_Target] = 76f; attribs.SendMessage(InGameClient, this.DynamicID); this.InGameClient.PacketId += 40 * 2; this.InGameClient.SendMessage(new DWordDataMessage() { Id = 0x89, Field0 = 0x0000007D //this.InGameClient.PacketId, }); this.InGameClient.FlushOutgoingBuffer(); }
public void UpdateExp(int addedExp) { GameAttributeMap attribs = new GameAttributeMap(); this.Attributes[GameAttribute.Experience_Next] -= addedExp; // Levelup if ((this.Attributes[GameAttribute.Experience_Next] <= 0) && (this.Attributes[GameAttribute.Level] < this.Attributes[GameAttribute.Level_Cap])) { this.Attributes[GameAttribute.Level]++; if (this.Attributes[GameAttribute.Level] < this.Attributes[GameAttribute.Level_Cap]) { this.Attributes[GameAttribute.Experience_Next] = this.Attributes[GameAttribute.Experience_Next] + LevelBorders[this.Attributes[GameAttribute.Level]]; } else { this.Attributes[GameAttribute.Experience_Next] = 0; } // todo: not always adding 2/2/2/1 on Levelup this.Attributes[GameAttribute.Defense] = 10f + (this.Attributes[GameAttribute.Level] - 1f) * 2f; this.Attributes[GameAttribute.Vitality] = 9f + (this.Attributes[GameAttribute.Level] - 1f) * 1f; this.Attributes[GameAttribute.Precision] = 11f + (this.Attributes[GameAttribute.Level] - 1f) * 2f; this.Attributes[GameAttribute.Attack] = 10f + (this.Attributes[GameAttribute.Level] - 1f) * 2f; attribs[GameAttribute.Level] = this.Attributes[GameAttribute.Level]; attribs[GameAttribute.Defense] = this.Attributes[GameAttribute.Defense]; attribs[GameAttribute.Vitality] = this.Attributes[GameAttribute.Vitality]; attribs[GameAttribute.Precision] = this.Attributes[GameAttribute.Precision]; attribs[GameAttribute.Attack] = this.Attributes[GameAttribute.Attack]; attribs[GameAttribute.Experience_Next] = this.Attributes[GameAttribute.Experience_Next]; attribs.SendMessage(this.InGameClient, this.DynamicID); this.InGameClient.SendMessage(new PlayerLevel() { Id = 0x98, Field0 = 0x00000000, Field1 = this.Attributes[GameAttribute.Level], }); this.InGameClient.SendMessage(new PlayEffectMessage() { Id = 0x7a, ActorID = this.DynamicID, Field1 = 6, }); this.InGameClient.SendMessage(new PlayEffectMessage() { Id = 0x7a, ActorID = this.DynamicID, Field1 = 32, Field2 = LevelUpEffects[this.Attributes[GameAttribute.Level]], }); } // constant 0 exp at Level_Cap if (this.Attributes[GameAttribute.Experience_Next] < 0) { this.Attributes[GameAttribute.Experience_Next] = 0; } attribs[GameAttribute.Experience_Next] = this.Attributes[GameAttribute.Experience_Next]; attribs.SendMessage(this.InGameClient, this.DynamicID); //this.Attributes.SendMessage(this.InGameClient, this.DynamicID); kills the player atm }
// FIXME: Hardcoded crap // FIXME: The new player stuff only needs to be called when the player joins the game public override void OnEnter(World world) { this.World.Reveal(this); // Notify the client of the new player InGameClient.SendMessage(new NewPlayerMessage { Field0 = 0x00000000, //Party frame (0x00000000 hide, 0x00000001 show) Field1 = "", //Owner name? ToonName = this.Properties.Name, Field3 = 0x00000002, //party frame class Field4 = 0x00000004, //party frame level snoActorPortrait = this.ClassSNO, //party frame portrait Field6 = 0x00000001, StateData = this.GetStateData(), Field8 = false, //announce party join Field9 = 0x00000001, ActorID = this.DynamicID, }); InGameClient.SendMessage(new ACDCollFlagsMessage { ActorID = this.DynamicID, CollFlags = 0x00000000, }); this.Attributes.SendMessage(InGameClient, this.DynamicID); // TODO: Pretty sure most of this stuff can be (and probably should be) put into Actor.Reveal() this.InGameClient.SendMessage(new ACDGroupMessage() { ActorID = this.DynamicID, Field1 = -1, Field2 = -1, }); this.InGameClient.SendMessage(new ANNDataMessage(Opcodes.ANNDataMessage7) { ActorID = this.DynamicID, }); this.InGameClient.SendMessage(new ACDTranslateFacingMessage(Opcodes.ACDTranslateFacingMessage1) { ActorID = this.DynamicID, Angle = 3.022712f, Field2 = false, }); this.InGameClient.SendMessage(new PlayerEnterKnownMessage() { Field0 = 0x00000000, PlayerID = this.DynamicID, }); this.InGameClient.SendMessage(new PlayerActorSetInitialMessage() { PlayerID = this.DynamicID, Field1 = 0x00000000, }); this.InGameClient.SendMessage(new SNONameDataMessage() { Name = new SNOName() { Group = 0x00000001, Handle = this.ClassSNO, }, }); this.InGameClient.FlushOutgoingBuffer(); this.InGameClient.SendMessage(new PlayerWarpedMessage() { Field0 = 9, Field1 = 0f, }); // This "tick" stuff is somehow required to use these values.. /komiga this.InGameClient.SendMessage(new DWordDataMessage() // TICK { Id = 0x0089, Field0 = 0x00000077, }); this.InGameClient.FlushOutgoingBuffer(); // FIXME: hackedy hack var attribs = new GameAttributeMap(); attribs[GameAttribute.Hitpoints_Healed_Target] = 76f; attribs.SendMessage(InGameClient, this.DynamicID); this.InGameClient.PacketId += 40 * 2; this.InGameClient.SendMessage(new DWordDataMessage() { Id = 0x89, Field0 = 0x0000007D //this.InGameClient.PacketId, }); this.InGameClient.FlushOutgoingBuffer(); }
public void Handle(GameClient client) { var player = client.Player; switch (this.Id) { case 0x0030: // Sent with DwordDataMessage(0x0125, Value:0) and SimpleMessage(0x0125) { // What the dickens is this stuff #region hardcoded1 #region Player Attribute Values GameAttributeMap attributes = new GameAttributeMap(); attributes[GameAttribute.Banter_Cooldown, 0xFFFFF] = 0x000007C9; attributes[GameAttribute.Buff_Active, 0x20CBE] = true; attributes[GameAttribute.Buff_Active, 0x33C40] = false; attributes[GameAttribute.Immobolize] = false; attributes[GameAttribute.Untargetable] = false; attributes[GameAttribute.CantStartDisplayedPowers] = false; attributes[GameAttribute.Buff_Icon_Start_Tick0, 0x20CBE] = 0xC1; attributes[GameAttribute.Disabled] = false; attributes[GameAttribute.Hidden] = false; attributes[GameAttribute.Buff_Icon_Count0, 0x33C40] = 0; attributes[GameAttribute.Buff_Icon_End_Tick0, 0x20CBE] = 0x7C9; attributes[GameAttribute.Loading] = false; attributes[GameAttribute.Buff_Icon_End_Tick0, 0x33C40] = 0; attributes[GameAttribute.Invulnerable] = false; attributes[GameAttribute.Buff_Icon_Count0, 0x20CBE] = 1; attributes[GameAttribute.Buff_Icon_Start_Tick0, 0x33C40] = 0; attributes.SendMessage(client, player.DynamicID); #endregion client.SendMessage(new ACDCollFlagsMessage() { ActorID = player.DynamicID, CollFlags = 0x00000008, }); client.SendMessage(new DWordDataMessage() { Id = 0x0089, Field0 = 0x000000C1, }); #endregion #region hardcoded2 // NOTE: This is very similar to ACDEnterKnown fields // TODO: Map proper values from the actor.. client.SendMessage(new TrickleMessage() { ActorId = player.DynamicID, ActorSNO = client.Player.ClassSNO, WorldLocation = new WorldPlace() { Position = new Vector3D() { X = 3143.75f, Y = 2828.75f, Z = 59.07559f, }, WorldID = client.Player.World.DynamicID, }, PlayerIndex = 0x00000000, LevelAreaSNO = 0x00026186, Field5 = 1f, Field6 = 0x00000001, Field7 = 0x00000024, Field10 = unchecked((int)0x8DFA5D13), StringListSNO = 0x0000F063, }); client.SendMessage(new DWordDataMessage() { Id = 0x0089, Field0 = 0x000000D1, }); #endregion } break; case 0x0028: // Logout complete (sent when delay timer expires on client side) //if (client.IsLoggingOut) //{ // client.SendMessageNow(new QuitGameMessage() // { // Id = 0x0003, // // Field0 - quit reason? // // 0 - logout // // 1 - kicked by party leader // // 2 - disconnected due to client-server (version?) missmatch // PlayerIndex = 0, // }); //} break; default: throw new NotImplementedException(); } }
public static bool Evaluate(int powerSNO, TagKeyScript scriptTag, GameAttributeMap attributes, Random rand, out float result) { result = 0; ScriptFormula scriptFormula = FindScriptFormula(powerSNO, scriptTag); if (scriptFormula == null) { //Logger.Error("could not find script tag {0} in power {1}", scriptTag.ID, powerSNO); return false; } byte[] script = scriptFormula.OpCodeArray; Stack<float> stack = new Stack<float>(4); // analysis of all stack formulas found the biggest stack is currently 11 int pos = 0; float numb1, numb2, numb3; float temp; while (pos < script.Length) { switch (script[pos]) { case 0: // return if (StackUnderflow(stack, 1)) return false; result = stack.Pop(); return true; case 1: // function pos += 4; switch (script[pos]) { case 0: // Min() if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(Math.Min(numb1, numb2)); break; case 1: // Max() if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(Math.Max(numb1, numb2)); break; case 2: // Pin() if (StackUnderflow(stack, 3)) return false; numb3 = stack.Pop(); numb2 = stack.Pop(); numb1 = stack.Pop(); if (numb2 > numb1) stack.Push(numb2); else if (numb1 > numb3) stack.Push(numb3); else stack.Push(numb1); break; case 3: // RandomIntMinRange() if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(rand.Next((int)numb1, (int)numb1 + (int)numb2)); break; case 4: // RandomIntMinMax() if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(rand.Next((int)numb1, (int)numb2)); break; case 5: // Floor() if (StackUnderflow(stack, 1)) return false; numb1 = stack.Pop(); stack.Push((float)Math.Floor(numb1)); break; case 9: // RandomFloatMinRange() if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 + (float)rand.NextDouble() * numb2); break; case 10: // RandomFloatMinMax() if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 + (float)rand.NextDouble() * (numb2 - numb1)); break; case 11: // Table() if (StackUnderflow(stack, 2)) return false; float index = stack.Pop(); float tableID = stack.Pop(); if (!LookupBalanceTable(tableID, index, out temp)) return false; stack.Push(temp); break; default: Logger.Error("Unimplemented function"); return false; } break; case 5: // external identifier if (!LoadIdentifier(powerSNO, scriptTag, attributes, rand, BitConverter.ToInt32(script, pos + 4 * 1), BitConverter.ToInt32(script, pos + 4 * 2), BitConverter.ToInt32(script, pos + 4 * 3), BitConverter.ToInt32(script, pos + 4 * 4), out temp)) return false; stack.Push(temp); pos += 4 * 4; break; case 6: // push float pos += 4; stack.Push(BitConverter.ToSingle(script, pos)); break; case 8: // operator > if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 > numb2 ? 1 : 0); break; case 11: // operator + if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 + numb2); break; case 12: // operator - if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 - numb2); break; case 13: // operator * if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 * numb2); break; case 14: // operator / if (StackUnderflow(stack, 2)) return false; numb2 = stack.Pop(); numb1 = stack.Pop(); if (numb2 == 0f) { Logger.Error("Division by zero, 0 pushed to stack instead of divide result"); stack.Push(0f); } else { stack.Push(numb1 / numb2); } break; case 16: // operator -(unary) if (StackUnderflow(stack, 1)) return false; numb1 = stack.Pop(); stack.Push(-numb1); break; case 17: // operator ?: if (StackUnderflow(stack, 3)) return false; numb3 = stack.Pop(); numb2 = stack.Pop(); numb1 = stack.Pop(); stack.Push(numb1 != 0 ? numb2 : numb3); break; default: Logger.Error("Unimplemented OpCode({0})", script[pos]); return false; } pos += 4; } // HACK: ignore bad formula if (powerSNO == Skills.Skills.Barbarian.FurySpenders.Whirlwind && scriptTag.ID == 266560) // ScriptFormula(4) { return true; } Logger.Error("script finished without return opcode"); return false; }
private static bool LoadAttribute(int powerSNO, GameAttributeMap attributes, int attributeId, out float result) { GameAttribute attr = GameAttribute.Attributes[attributeId]; bool needs_key = _powerKeyedAttributes.Contains(attributeId); if (attr is GameAttributeF) { if (needs_key) result = attributes[(GameAttributeF)attr, powerSNO]; else result = attributes[(GameAttributeF)attr]; return true; } else if (attr is GameAttributeI) { if (needs_key) result = (float)attributes[(GameAttributeI)attr, powerSNO]; else result = (float)attributes[(GameAttributeI)attr]; return true; } else if (attr is GameAttributeB) { if (needs_key) result = attributes[(GameAttributeB)attr, powerSNO] ? 1 : 0; else result = attributes[(GameAttributeB)attr] ? 1 : 0; return true; } else { Logger.Error("invalid attribute {0}", attributeId); result = 0; return false; } }
private static bool LoadIdentifier(int powerSNO, TagKeyScript scriptTag, GameAttributeMap attributes, Random rand, int numb1, int numb2, int numb3, int numb4, out float result) { switch (numb1) { case 0: return LoadAttribute(powerSNO, attributes, numb2, out result); case 1: // slevel result = attributes[GameAttribute.Skill, powerSNO]; return true; case 22: // absolute power formula ref return Evaluate(numb2, new TagKeyScript(numb3), attributes, rand, out result); default: if (numb1 >= 23 && numb1 <= 62) // SF_N, relative power formula ref { int SF_N = numb1 - 23; TagKeyScript relativeTag = PowerTagHelper.GenerateTagForScriptFormula(SF_N); return Evaluate(powerSNO, relativeTag, attributes, rand, out result); } else if (numb1 >= 63 && numb1 <= 72) // known gamebalance power table id range { result = BinaryIntToFloat(numb1); // simply store id, used later by Table() return true; } else { Logger.Error("unknown identifier"); result = 0; return false; } } }
public void UpdateExp(int addedExp) { GameAttributeMap attribs = new GameAttributeMap(); this.Attributes[GameAttribute.Experience_Next] -= addedExp; // Levelup if ((this.Attributes[GameAttribute.Experience_Next] <= 0) && (this.Attributes[GameAttribute.Level] < this.Attributes[GameAttribute.Level_Cap])) { this.Attributes[GameAttribute.Level]++; this.Properties.LevelUp(); if (this.Attributes[GameAttribute.Level] < this.Attributes[GameAttribute.Level_Cap]) { this.Attributes[GameAttribute.Experience_Next] = this.Attributes[GameAttribute.Experience_Next] + LevelBorders[this.Attributes[GameAttribute.Level]]; } else { this.Attributes[GameAttribute.Experience_Next] = 0; } // 4 main attributes are incremented according to class this.Attributes[GameAttribute.Attack] += this.AttackIncrement; this.Attributes[GameAttribute.Precision] += this.PrecisionIncrement; this.Attributes[GameAttribute.Vitality] += this.VitalityIncrement; this.Attributes[GameAttribute.Defense] += this.DefenseIncrement; // Hitpoints from level may actually change. This needs to be verified by someone with the beta. //this.Attributes[GameAttribute.Hitpoints_Total_From_Level] = this.Attributes[GameAttribute.Level] * this.Attributes[GameAttribute.Hitpoints_Factor_Level]; // For now, hit points are based solely on vitality and initial hitpoints received. // This will have to change when hitpoint bonuses from items are implemented. this.Attributes[GameAttribute.Hitpoints_Total_From_Vitality] = this.Attributes[GameAttribute.Vitality] * this.Attributes[GameAttribute.Hitpoints_Factor_Vitality]; this.Attributes[GameAttribute.Hitpoints_Max] = GetMaxTotalHitpoints(); this.Attributes[GameAttribute.Hitpoints_Max_Total] = GetMaxTotalHitpoints(); // On level up, health is set to max this.Attributes[GameAttribute.Hitpoints_Cur] = this.Attributes[GameAttribute.Hitpoints_Max_Total]; attribs[GameAttribute.Level] = this.Attributes[GameAttribute.Level]; attribs[GameAttribute.Defense] = this.Attributes[GameAttribute.Defense]; attribs[GameAttribute.Vitality] = this.Attributes[GameAttribute.Vitality]; attribs[GameAttribute.Precision] = this.Attributes[GameAttribute.Precision]; attribs[GameAttribute.Attack] = this.Attributes[GameAttribute.Attack]; attribs[GameAttribute.Experience_Next] = this.Attributes[GameAttribute.Experience_Next]; attribs[GameAttribute.Hitpoints_Total_From_Vitality] = this.Attributes[GameAttribute.Hitpoints_Total_From_Vitality]; attribs[GameAttribute.Hitpoints_Max_Total] = this.Attributes[GameAttribute.Hitpoints_Max_Total]; attribs[GameAttribute.Hitpoints_Max] = this.Attributes[GameAttribute.Hitpoints_Max]; attribs[GameAttribute.Hitpoints_Cur] = this.Attributes[GameAttribute.Hitpoints_Cur]; attribs.SendMessage(this.InGameClient, this.DynamicID); this.InGameClient.SendMessage(new PlayerLevel() { Id = 0x98, Field0 = 0x00000000, Field1 = this.Attributes[GameAttribute.Level], }); this.InGameClient.SendMessage(new PlayEffectMessage() { ActorId = this.DynamicID, Effect = Effect.LevelUp, }); this.World.BroadcastGlobal(new PlayEffectMessage() { ActorId = this.DynamicID, Effect = Effect.PlayEffectGroup, OptionalParameter = LevelUpEffects[this.Attributes[GameAttribute.Level]], }); } // constant 0 exp at Level_Cap if (this.Attributes[GameAttribute.Experience_Next] < 0) { this.Attributes[GameAttribute.Experience_Next] = 0; } attribs[GameAttribute.Experience_Next] = this.Attributes[GameAttribute.Experience_Next]; attribs.SendMessage(this.InGameClient, this.DynamicID); //this.Attributes.SendMessage(this.InGameClient, this.DynamicID); kills the player atm }
// simple static reresh public void RefreshStatistic() { var attribs = new GameAttributeMap(); // min demage this.Attributes[GameAttribute.Damage_Weapon_Min_Total_CurrentHand, 0] = this.Attributes[GameAttribute.Damage_Weapon_Min_Total_MainHand, 0];// only main hand "(DualWield_Hand#NONE ? Damage_Weapon_Min_Total_OffHand : Damage_Weapon_Min_Total_MainHand)" this.Attributes[GameAttribute.Damage_Min_Subtotal, 0] = this.Attributes[GameAttribute.Damage_Min, 0] + this.Attributes[GameAttribute.Damage_Bonus_Min, 0] + this.Attributes[GameAttribute.Damage_Weapon_Min_Total_CurrentHand, 0]; this.Attributes[GameAttribute.Damage_Min_Total, 0] = this.Attributes[GameAttribute.Damage_Min_Subtotal, 0] + this.Attributes[GameAttribute.Damage_Type_Percent_Bonus, 0] * this.Attributes[GameAttribute.Damage_Min_Subtotal, 0]; // delta demage this.Attributes[GameAttribute.Damage_Weapon_Delta_Total_CurrentHand, 0] = this.Attributes[GameAttribute.Damage_Weapon_Delta_Total_MainHand, 0];// only main hand "(DualWield_Hand#NONE ? Damage_Weapon_Min_Total_OffHand : Damage_Weapon_Min_Total_MainHand)" this.Attributes[GameAttribute.Damage_Delta_Total, 0] = Math.Max(this.Attributes[GameAttribute.Damage_Delta, 0] - this.Attributes[GameAttribute.Damage_Bonus_Min, 0] + this.Attributes[GameAttribute.Damage_Weapon_Delta_Total_CurrentHand, 0], 0); // attack speed hack this.Attributes[GameAttribute.Attacks_Per_Second_Item_CurrentHand] = this.Attributes[GameAttribute.Attacks_Per_Second_Item_MainHand]; this.Attributes[GameAttribute.Attacks_Per_Second_Total] = this.Attributes[GameAttribute.Attacks_Per_Second_Item_CurrentHand]; attribs[GameAttribute.Damage_Min_Total, 0] = this.Attributes[GameAttribute.Damage_Min_Total, 0]; attribs[GameAttribute.Damage_Delta_Total, 0] = this.Attributes[GameAttribute.Damage_Delta_Total, 0]; attribs[GameAttribute.Attacks_Per_Second_Total] = this.Attributes[GameAttribute.Attacks_Per_Second_Total]; attribs.SendMessage(InGameClient, DynamicID); }