From d9f164d5da5903af5a389df35bb890a93fb1dbad Mon Sep 17 00:00:00 2001 From: NLObP <38990417+NL0bP@users.noreply.github.com> Date: Tue, 11 Mar 2025 21:49:06 +0300 Subject: [PATCH 1/3] Client version/5.0 client (2018 12 25) (#1210) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Основные изменения на 19 октября 2024 года: [Game] Особенность: подключил базу версии 5.0.7.0; - в базе английская локализация, поэтому в файле Config.json должна быть строка "DefaultLanguage": "en_us"; [Packets] Исправил структуры пакетов для лута; [Login] Установил 4 открытых слота для создания персонажей; [Game] Исправил слоты действий: - в версии 5+ MaxActionSlots=157, вместо 133 для 3+; [Game] Исправил работу баффа; [Game] Автоматическая юстировка констант шифрации. [Game] Исправлен бафф Dash: - теперь мана расходуется при беге; - используем формулу трата маны=3.33*уровень+11.67 [SQL] Добавлен файл loots_5070_add_memory-ember.sql: - Исправляем ошибку: В камине нельзя взять уголёк Id=36917 "Memory Ember" [SQL] Изменил поле `slot_type` с enum на int: - добавлен файл 2024-09-16_aaemu_game_item_containers_update.sql; - добавлен файл 2024-09-16_aaemu_game_items_update.sql; - обновлен файл aaemu_game.sql. [Game] Внесены изменения в код: - Теперь работает Divine Clock; - Получаем подарки за онлайн в игре. - Теперь подарки, которые будут вручены выбираются из расписания; [Game] Исправлен домашний портал: - Можно переименовать/удалить домашний портал; [Data] Исправил точки крепления для домов (сгенерировано плагином HousingBindings); [SQL] Добавлен файл 2024-06-09_aaemu_game_divine_clock.sql: - Таблица 'divine_clock' осуществляет поддержку выдачи подарков за нахождение в онлайн в игре; [Game] Исправил возможность покинуть транспорт; [Game] Исправил возможность переименовать питомцев, транспорт и дома; [Game] WIP: начато исправление аукциона; - Сохранение в базу предметов аукциона - не реализовано; Исправление поиска предметов: - постраничное листание списка лотов; - Добавлен определитель языка для keyword. - Для правильного поиска по аукциону потребуется добавить переводы в серверную базу, иначе не будет поиска на родном языке. - Пока поиск будет только на английском языке; Продажа: - показывает только список лотов, которые игрок выставил на продажу; Ставки: - Можно делать ставки; - Отображается в каких лотах мы сделали ставку; - Добавлен вывод только наших ставок. - Для целей проверки ставка вместо 6 часов будет продолжаться 6 минут; - Добавлен частичный выкуп лота; [SQL] обновлены aaemu_game.sql и добавлен 2024-10-04_aaemu_game_auction_house_update.sql [Game] WIP: начато исправление группы; [Game] Исправление инициализации инвентаря; [Game] Исправлено назначение владельца предмета при разделении стопки на две части; [Game] Исправление почты: - исправил принятие почты; - теперь почта не пропадает при закрытии письма; - при получении прикрепленных предметов к письму, пустое письмо можно сразу удалить (активируется кнопка удаления); [Game] Исправление покупки/продажи у Npc; [Game] Исправил возможность ставить/убирать оборудование на корабли; * Основные изменения на 29 октября 2024 года: [Game] WIP: исправление аукциона: - Добавлено сохранение в базу данных; [Game] Добавлены перечисления MailBoxListKind, SystemMailSenderKind; - перемещены все `enum` файлы в Mail\Static [Game] WIP: исправление аукциона: - Исправил покупку части аукционного лота; [SQL] updated aaemu_game.sql and added 2024-10-25_aaemu_game_auction_house_update.sql [Game] WIP: исправление аукциона: - добавил расчёт и сохранение динамики продаж; [SQL] updated aaemu_game.sql and added 2024-10-28_aaemu_game_auction_solds_data_update.sql --- .../Cryptography/ConnectionKeychain.cs | 4 + .../Cryptography/EncryptionManager.cs | 93 +- AAEmu.Commons/Network/PacketStream.cs | 1 - AAEmu.Game/AAEmu.Game.csproj | 4 + AAEmu.Game/Configurations/xorKeyValue.txt | 4 + AAEmu.Game/Core/Managers/AccountManager.cs | 214 +- AAEmu.Game/Core/Managers/AuctionManager.cs | 1098 +++-- .../Core/Managers/GameScheduleManager.cs | 69 + AAEmu.Game/Core/Managers/HousingManager.cs | 27 +- AAEmu.Game/Core/Managers/ItemManager.cs | 49 +- AAEmu.Game/Core/Managers/MailManager.cs | 23 +- AAEmu.Game/Core/Managers/ManaRegenManager.cs | 64 + AAEmu.Game/Core/Managers/MateManager.cs | 21 +- AAEmu.Game/Core/Managers/PortalManager.cs | 5 +- AAEmu.Game/Core/Managers/ShipyardManager.cs | 6 +- AAEmu.Game/Core/Managers/SkillManager.cs | 17 + AAEmu.Game/Core/Managers/SlaveManager.cs | 47 +- AAEmu.Game/Core/Managers/Stream/UccManager.cs | 6 +- .../Core/Managers/TimedRewardsManager.cs | 26 +- AAEmu.Game/Core/Managers/TradeManager.cs | 4 +- .../Managers/UnitManagers/CharacterManager.cs | 5 +- .../Managers/UnitManagers/DoodadManager.cs | 4 +- .../Core/Managers/UnitManagers/NpcManager.cs | 9 +- .../Core/Managers/World/SpecialtyManager.cs | 4 +- .../Core/Managers/World/WorldManager.cs | 18 +- AAEmu.Game/Core/Managers/World/ZoneManager.cs | 14 +- AAEmu.Game/Core/Network/Game/GameNetwork.cs | 58 +- AAEmu.Game/Core/Network/Game/GamePacket.cs | 3 +- .../Core/Network/Game/GameProtocolHandler.cs | 11 +- .../Core/Packets/C2G/CSAuctionBidPacket.cs | 45 +- .../Core/Packets/C2G/CSAuctionCancelPacket.cs | 44 +- .../Packets/C2G/CSAuctionLowestPricePacket.cs | 8 +- .../Packets/C2G/CSAuctionMyBidListPacket.cs | 8 +- .../Core/Packets/C2G/CSAuctionPostPacket.cs | 13 +- .../Core/Packets/C2G/CSAuctionSearchPacket.cs | 29 +- .../C2G/CSAuctionSearchSoldRecordPacket.cs | 15 +- .../Core/Packets/C2G/CSBidAuctionPacket.cs | 53 - .../C2G/CSBroadcastVisualOption_0_Packet.cs | 36 +- .../Core/Packets/C2G/CSBuyItemsPacket.cs | 33 +- .../Core/Packets/C2G/CSCancelAuctionPacket.cs | 47 - .../C2G/CSChangeAutoUseAaPointPacket.cs | 16 + .../C2G/CSChangeClientNpcTargetPacket.cs | 16 + .../C2G/CSChangeMateEquipmentPacket.cs | 2 +- .../C2G/CSChangeSlaveEquipmentPacket.cs | 114 +- .../Packets/C2G/CSChangeSlaveNamePacket.cs | 4 + .../Packets/C2G/CSCompletedTutorialPacket.cs | 2 + .../Core/Packets/C2G/CSDemoCharResetPacket.cs | 16 + .../Core/Packets/C2G/CSDepositMoneyPacket.cs | 2 +- .../Core/Packets/C2G/CSHeroAbstainPacket.cs | 16 + .../Packets/C2G/CSHeroCandidateListPacket.cs | 16 + .../Packets/C2G/CSHeroRankingListPacket.cs | 16 + .../Core/Packets/C2G/CSHeroVotingPacket.cs | 16 + .../Packets/C2G/CSInteractGimmickPacket.cs | 16 + .../Core/Packets/C2G/CSJurySentencePacket.cs | 16 + .../Packets/C2G/CSListMailContinuePacket.cs | 2 + .../Core/Packets/C2G/CSListMailPacket.cs | 2 +- .../Core/Packets/C2G/CSListSoldItemPacket.cs | 2 + .../C2G/CSNotifyInGameCompletedPacket.cs | 3 +- .../Core/Packets/C2G/CSNotifyInGamePacket.cs | 31 +- AAEmu.Game/Core/Packets/C2G/CSOffsets.cs | 28 +- ...TaxPacket.cs => CSPrepayHouseTaxPacket.cs} | 6 +- .../Core/Packets/C2G/CSRankSnapshotPacket.cs | 16 + .../C2G/CSRemoveAllFieldSlavesPacket.cs | 22 + .../Packets/C2G/CSRequestSetBountyPacket.cs | 16 + .../Core/Packets/C2G/CSSearchListPacket.cs | 4 + .../Packets/C2G/CSSelectCharacterPacket.cs | 37 +- .../Core/Packets/C2G/CSSellItemsPacket.cs | 36 +- .../CSSendExpeditionImmigrationListPacket.cs | 16 + .../Core/Packets/C2G/CSSendMailPacket.cs | 1 + .../Packets/C2G/CSSendNationInfoSetPacket.cs | 16 + .../C2G/CSSendNationMemberCountListPacket.cs | 16 + .../Packets/C2G/CSSendRelationFriendPacket.cs | 16 + .../Packets/C2G/CSSendRelationVotePacket.cs | 16 + .../C2G/CSSkillControllerStatePacket.cs | 21 - .../Core/Packets/C2G/CSStartSkillPacket.cs | 13 +- .../Core/Packets/C2G/CSStoppedCinemaPacket.cs | 17 + .../C2G/CSTakeAllAttachmentItemPacket.cs | 2 +- .../C2G/CSTakeAttachmentSequentially.cs | 28 - .../Packets/C2G/CSTakeScheduleItemPacket.cs | 54 + .../Core/Packets/C2G/CSUpdateBountyPacket.cs | 16 + .../Core/Packets/C2G/CSWithdrawMoneyPacket.cs | 2 +- .../Packets/C2G/CSWorldRaycastingPacket.cs | 16 + .../Core/Packets/G2C/SCAddHousePacket.cs | 29 + .../Packets/G2C/SCAttachmentTakenPacket.cs | 26 +- .../Core/Packets/G2C/SCAuctionBidPacket.cs | 22 +- .../Packets/G2C/SCAuctionCanceledPacket.cs | 37 +- .../Packets/G2C/SCAuctionLowestPricePacket.cs | 21 +- .../Packets/G2C/SCAuctionMessagePacket.cs | 28 + .../Core/Packets/G2C/SCAuctionPostedPacket.cs | 38 +- .../Packets/G2C/SCAuctionSearchedPacket.cs | 60 +- .../Packets/G2C/SCAuctionSoldRecordPacket.cs | 40 +- .../G2C/SCCharacterLaborPowerChangedPacket.cs | 2 + .../Packets/G2C/SCCompletedQuestsPacket.cs | 16 +- .../Core/Packets/G2C/SCCoolDownPacket.cs | 11 +- .../Core/Packets/G2C/SCDailyCountPacket.cs | 27 + .../G2C/SCDelayedTaskOnInGameNotifyPacket.cs | 17 + .../Core/Packets/G2C/SCICSSyncGoodPacket.cs | 23 - .../Core/Packets/G2C/SCICSSyncGoodsPacket.cs | 4 +- .../Core/Packets/G2C/SCImpulseUnitPacket.cs | 52 + .../Packets/G2C/SCItemTaskNotifyPacket.cs | 40 + .../Packets/G2C/SCItemTaskSuccessPacket.cs | 10 +- .../Core/Packets/G2C/SCMailFailedPacket.cs | 2 +- .../Packets/G2C/SCMailStatusUpdatedPacket.cs | 2 +- .../G2C/SCMateEquipmentChangedPacket.cs | 1 - .../Core/Packets/G2C/SCMateStatusPacket.cs | 1 - AAEmu.Game/Core/Packets/G2C/SCOffsets.cs | 40 +- .../G2C/SCQuestContextCompletedPacket.cs | 2 +- .../Packets/G2C/SCQuestContextResetPacket.cs | 4 +- .../G2C/SCQuestContextStartedPacket.cs | 2 +- .../G2C/SCQuestContextUpdatedPacket.cs | 2 +- AAEmu.Game/Core/Packets/G2C/SCQuestsPacket.cs | 15 +- .../Packets/G2C/SCRaceCongestionPacket.cs | 2 + .../G2C/SCRebuildHouseTaxInfoPacket.cs | 50 + .../Packets/G2C/SCReputationChangedPacket.cs | 26 + .../Packets/G2C/SCScheduleItemSentPacket.cs | 23 + .../Packets/G2C/SCScheduleItemUpdatePacket.cs | 3 +- .../Packets/G2C/SCSkillCooldownResetPacket.cs | 19 +- .../Core/Packets/G2C/SCSkillFiredPacket.cs | 190 +- .../Core/Packets/G2C/SCSkillLearnedPacket.cs | 2 +- .../Core/Packets/G2C/SCSkillStartedPacket.cs | 38 +- AAEmu.Game/Core/Packets/G2C/SCSkillStopped.cs | 25 - .../Core/Packets/G2C/SCSlaveStatusPacket.cs | 5 +- .../Core/Packets/G2C/SCSoldItemListPacket.cs | 2 +- ...linkUnitPacket.cs => SCUnitBlinkPacket.cs} | 12 +- .../G2C/SCUnitEquipmentsChangedPacket.cs | 6 +- .../Core/Packets/G2C/SCUnitStatePacket.cs | 10 +- .../G2C/SCUpdateSkillActiveTypePacket.cs | 11 +- .../Core/Packets/Proxy/FinishStatePacket.cs | 2 +- .../instance_carcass/doodad_spawns.json | 1 + .../Worlds/instance_carcass/npc_spawns.json | 1 + .../doodad_spawns.json | 1 + .../instance_challenge_tower/npc_spawns.json | 1 + .../doodad_spawns.json | 1 + .../instance_defense_of_feast/npc_spawns.json | 1 + .../instance_dew_plain/doodad_spawns.json | 1 + .../Worlds/instance_dew_plain/npc_spawns.json | 1 + .../instance_dewplane_boss/doodad_spawns.json | 1 + .../instance_dewplane_boss/npc_spawns.json | 1 + .../instance_eternity/doodad_spawns.json | 1 + .../Worlds/instance_eternity/npc_spawns.json | 1 + .../instance_golden_plains/doodad_spawns.json | 1 + .../instance_golden_plains/npc_spawns.json | 1 + .../doodad_spawns.json | 1 + .../npc_spawns.json | 1 + .../doodad_spawns.json | 1 + .../npc_spawns.json | 1 + .../instance_library_new/doodad_spawns.json | 1 + .../instance_library_new/npc_spawns.json | 1 + .../doodad_spawns.json | 1 + .../instance_library_new_boss/npc_spawns.json | 1 + .../doodad_spawns.json | 1 + .../instance_sal_temple_hard/npc_spawns.json | 1 + .../instance_sea_survival/doodad_spawns.json | 1 + .../instance_sea_survival/npc_spawns.json | 1 + .../doodad_spawns.json | 1 + .../instance_sea_survival_2/npc_spawns.json | 1 + .../doodad_spawns.json | 1 + .../instance_sea_survival_4/npc_spawns.json | 1 + .../doodad_spawns.json | 1 + .../npc_spawns.json | 1 + AAEmu.Game/Data/housing_bindings.json | 4122 ++++++++++++----- AAEmu.Game/GameData/SchedulesGameData.cs | 55 + AAEmu.Game/GameService.cs | 1 + .../Game/Attendance/CharacterAttendances.cs | 4 +- AAEmu.Game/Models/Game/Auction/AuctionBid.cs | 34 + .../Models/Game/Auction/AuctionDisplay.cs | 25 + .../Models/Game/Auction/AuctionDuration.cs | 9 + AAEmu.Game/Models/Game/Auction/AuctionItem.cs | 105 - AAEmu.Game/Models/Game/Auction/AuctionLot.cs | 78 + .../Models/Game/Auction/AuctionSearch.cs | 65 + .../Game/Auction/AuctionSearchSortKind.cs | 12 + .../Game/Auction/AuctionSearchSortOrder.cs | 7 + AAEmu.Game/Models/Game/Auction/AuctionSold.cs | 285 ++ .../Templates/AuctionSearchTemplate.cs | 22 - AAEmu.Game/Models/Game/Char/Character.cs | 16 +- .../Models/Game/Char/CharacterActability.cs | 2 +- AAEmu.Game/Models/Game/Char/CharacterCraft.cs | 2 +- AAEmu.Game/Models/Game/Char/CharacterMails.cs | 88 +- AAEmu.Game/Models/Game/Char/CharacterMates.cs | 2 +- .../Models/Game/Char/CharacterPortals.cs | 68 +- .../Models/Game/Char/CharacterQuests.cs | 7 +- AAEmu.Game/Models/Game/Char/Inventory.cs | 83 +- AAEmu.Game/Models/Game/DoodadObj/Doodad.cs | 26 +- .../Game/DoodadObj/Funcs/DoodadFuncBuyFish.cs | 2 +- .../DoodadObj/Funcs/DoodadFuncLootItem.cs | 2 +- .../DoodadObj/Funcs/DoodadFuncRecoverItem.cs | 2 +- .../Game/DoodadObj/Static/AttachUnitReason.cs | 4 +- AAEmu.Game/Models/Game/ErrorMessageType.cs | 2023 ++++---- AAEmu.Game/Models/Game/Gimmicks/Gimmick.cs | 2 +- AAEmu.Game/Models/Game/Housing/House.cs | 14 + .../Game/Items/Actions/AAPointUpdate.cs | 1 + .../Items/Actions/ChangeAutoUseAAPoint.cs | 3 +- .../Game/Items/Actions/ChangeBankAAPoint.cs | 1 + .../Game/Items/Actions/ChangeGamePoint.cs | 3 +- .../Models/Game/Items/Actions/ItemAction.cs | 2 +- .../Models/Game/Items/Actions/ItemAdd.cs | 18 +- .../Models/Game/Items/Actions/ItemAddNew.cs | 25 +- .../Models/Game/Items/Actions/ItemBuyback.cs | 10 +- .../Game/Items/Actions/ItemCountUpdate.cs | 1 + .../Game/Items/Actions/ItemGradeChange.cs | 3 +- .../Models/Game/Items/Actions/ItemMove.cs | 3 + .../Models/Game/Items/Actions/ItemRemove.cs | 36 +- .../Game/Items/Actions/ItemRemoveCrafting.cs | 3 +- .../Game/Items/Actions/ItemRemoveSlot.cs | 2 + .../Models/Game/Items/Actions/ItemTask.cs | 77 +- .../Game/Items/Actions/ItemTaskLogType.cs | 9 + .../Models/Game/Items/Actions/ItemTaskType.cs | 297 +- .../Models/Game/Items/Actions/ItemUpdate.cs | 2 +- .../Game/Items/Actions/ItemUpdateBits.cs | 1 + .../Game/Items/Actions/ItemUpdateRepair.cs | 1 + .../Game/Items/Actions/ItemUpdateSecurity.cs | 3 +- .../Models/Game/Items/Actions/MoneyChange.cs | 2 + .../Items/Actions/UpdateChargeUseSkillTime.cs | 3 +- .../Models/Game/Items/AuctionSettings.cs | 19 + .../Game/Items/Containers/CofferContainer.cs | 2 +- .../Items/Containers/EquipmentContainer.cs | 2 +- .../Game/Items/Containers/ItemContainer.cs | 52 +- .../Containers/SlaveEquipmentContainer.cs | 93 +- AAEmu.Game/Models/Game/Items/Item.cs | 19 +- .../Models/Game/Items/Loots/LootPack.cs | 2 +- AAEmu.Game/Models/Game/Items/SlotType.cs | 72 +- AAEmu.Game/Models/Game/Items/SummonMate.cs | 15 +- .../Game/Items/Templates/ItemTemplate.cs | 6 + AAEmu.Game/Models/Game/Mails/BaseMail.cs | 3 +- .../Models/Game/Mails/CommercialMail.cs | 3 +- .../Models/Game/Mails/CountUnreadMail.cs | 18 +- AAEmu.Game/Models/Game/Mails/MailBody.cs | 1 + .../Models/Game/Mails/MailForAuction.cs | 14 +- .../Models/Game/Mails/MailForSpeciality.cs | 9 +- AAEmu.Game/Models/Game/Mails/MailForTax.cs | 3 +- AAEmu.Game/Models/Game/Mails/MailHeader.cs | 1 + .../Models/Game/Mails/MailPlayerToPlayer.cs | 5 +- .../Mails/{ => Static}/CommercialMailTypes.cs | 2 +- .../Game/Mails/Static/MailBoxListKind.cs | 10 + .../Game/Mails/{ => Static}/MailResult.cs | 2 +- .../Game/Mails/{ => Static}/MailStatus.cs | 2 +- .../Game/Mails/{ => Static}/MailType.cs | 2 +- .../Game/Mails/{ => Static}/MiaMailTypes.cs | 2 +- .../Game/Mails/Static/SystemMailSenderKind.cs | 7 + .../Game/Quests/Acts/QuestActConAcceptItem.cs | 2 +- .../Quests/Acts/QuestActConAcceptItemGain.cs | 2 +- .../Quests/Acts/QuestActSupplyRemoveItem.cs | 2 +- AAEmu.Game/Models/Game/Quests/NewQuestCode.cs | 2 + AAEmu.Game/Models/Game/Quests/Quest.cs | 5 +- AAEmu.Game/Models/Game/ScheduleItem.cs | 8 +- .../Models/Game/Schedules/ScheduleItems.cs | 37 + .../Models/Game/Skills/BuffConstants.cs | 3 +- .../Game/Skills/Buffs/ManaRegenTemplate.cs | 65 + .../Game/Skills/Effects/CleanupUccEffect.cs | 2 +- .../Game/Skills/Effects/ImprintUccEffect.cs | 2 +- .../Game/Skills/Effects/ImpulseEffect.cs | 12 +- .../Skills/Effects/MoveToLocationEffect.cs | 37 + .../Skills/Effects/PutDownBackpackEffect.cs | 2 +- .../Skills/Effects/SpecialEffects/Blink.cs | 4 +- .../Effects/SpecialEffects/GradeEnchant.cs | 4 +- .../Effects/SpecialEffects/SpawnDoodad.cs | 46 +- .../Effects/SpecialEffects/TeleportToUnit.cs | 2 +- AAEmu.Game/Models/Game/Skills/Skill.cs | 36 +- AAEmu.Game/Models/Game/Skills/SkillCaster.cs | 30 +- .../Models/Game/Skills/SkillConstants.cs | 1 + AAEmu.Game/Models/Game/Skills/SkillObject.cs | 190 +- .../Models/Game/Skills/Static/SkillResult.cs | 841 ++-- .../Game/Skills/Templates/BuffTemplate.cs | 5 + AAEmu.Game/Models/Game/Units/Mate.cs | 2 +- AAEmu.Game/Models/Game/Units/Slave.cs | 29 +- .../Game/Units/Static/UnitReqsKindType.cs | 212 +- AAEmu.Game/Models/Game/Units/UnitAttribute.cs | 354 +- AAEmu.Game/Models/Game/Units/UnitReqs.cs | 2 +- .../Models/Game/World/Zones/IndunZone.cs | 2 +- .../Models/Tasks/CashShop/CashShopBuyTask.cs | 2 +- .../Characters/CharacterOnlineTrackingTask.cs | 78 +- AAEmu.Game/Scripts/Commands/AddPortals.cs | 3 +- AAEmu.Game/Scripts/Commands/ShowInventory.cs | 6 +- .../Scripts/Commands/TestAuctionHouse.cs | 52 +- AAEmu.Game/Scripts/Commands/TestMails.cs | 3 +- .../Scripts/Commands/WipeAuctionHouse.cs | 4 +- .../WebApi/Controllers/AuctionController.cs | 79 +- .../WebApi/Controllers/MailController.cs | 5 +- .../Services/WebApi/Models/SendMailRequest.cs | 1 + .../Core/Controllers/LoginController.cs | 6 +- .../Game/Core/Managers/MailTests.cs | 1 + .../Game/Items/Containers/InventoryTests.cs | 2 +- Docs/Docker-Installation-Guide.md | 2 +- SQL/aaemu_game.sql | 1003 ++-- .../loots_5070_add_memory-ember.sql | 15 + .../2024-06-09_aaemu_game_divine_clock.sql | 23 + ...9-16_aaemu_game_item_containers_update.sql | 8 + .../2024-09-16_aaemu_game_items_update.sql | 7 + ...-10-04_aaemu_game_auction_house_update.sql | 39 + .../2024-10-06_aaemu_game_auction_sold.sql | 15 + ...-10-25_aaemu_game_auction_house_update.sql | 26 + ...8_aaemu_game_auction_solds_data_update.sql | 16 + 292 files changed, 10467 insertions(+), 4903 deletions(-) create mode 100644 AAEmu.Game/Configurations/xorKeyValue.txt create mode 100644 AAEmu.Game/Core/Managers/ManaRegenManager.cs delete mode 100644 AAEmu.Game/Core/Packets/C2G/CSBidAuctionPacket.cs delete mode 100644 AAEmu.Game/Core/Packets/C2G/CSCancelAuctionPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSChangeAutoUseAaPointPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSChangeClientNpcTargetPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSDemoCharResetPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSHeroAbstainPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSHeroCandidateListPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSHeroRankingListPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSHeroVotingPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSInteractGimmickPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSJurySentencePacket.cs rename AAEmu.Game/Core/Packets/C2G/{CSPerpayHouseTaxPacket.cs => CSPrepayHouseTaxPacket.cs} (70%) create mode 100644 AAEmu.Game/Core/Packets/C2G/CSRankSnapshotPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSRemoveAllFieldSlavesPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSRequestSetBountyPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSSendExpeditionImmigrationListPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSSendNationInfoSetPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSSendNationMemberCountListPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSSendRelationFriendPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSSendRelationVotePacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSStoppedCinemaPacket.cs delete mode 100644 AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentSequentially.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSTakeScheduleItemPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSUpdateBountyPacket.cs create mode 100644 AAEmu.Game/Core/Packets/C2G/CSWorldRaycastingPacket.cs create mode 100644 AAEmu.Game/Core/Packets/G2C/SCAddHousePacket.cs create mode 100644 AAEmu.Game/Core/Packets/G2C/SCAuctionMessagePacket.cs create mode 100644 AAEmu.Game/Core/Packets/G2C/SCDailyCountPacket.cs create mode 100644 AAEmu.Game/Core/Packets/G2C/SCDelayedTaskOnInGameNotifyPacket.cs delete mode 100644 AAEmu.Game/Core/Packets/G2C/SCICSSyncGoodPacket.cs create mode 100644 AAEmu.Game/Core/Packets/G2C/SCImpulseUnitPacket.cs create mode 100644 AAEmu.Game/Core/Packets/G2C/SCItemTaskNotifyPacket.cs create mode 100644 AAEmu.Game/Core/Packets/G2C/SCRebuildHouseTaxInfoPacket.cs create mode 100644 AAEmu.Game/Core/Packets/G2C/SCReputationChangedPacket.cs create mode 100644 AAEmu.Game/Core/Packets/G2C/SCScheduleItemSentPacket.cs delete mode 100644 AAEmu.Game/Core/Packets/G2C/SCSkillStopped.cs rename AAEmu.Game/Core/Packets/G2C/{SCBlinkUnitPacket.cs => SCUnitBlinkPacket.cs} (64%) create mode 100644 AAEmu.Game/Data/Worlds/instance_carcass/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_carcass/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_challenge_tower/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_challenge_tower/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_defense_of_feast/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_defense_of_feast/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_dew_plain/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_dew_plain/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_dewplane_boss/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_dewplane_boss/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_eternity/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_eternity/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_golden_plains/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_golden_plains/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_golden_plains_war/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_golden_plains_war/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_hanging_gardens_of_ipna/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_hanging_gardens_of_ipna/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_library_new/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_library_new/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_library_new_boss/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_library_new_boss/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_sal_temple_hard/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_sal_temple_hard/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_sea_survival/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_sea_survival/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_sea_survival_2/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_sea_survival_2/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_sea_survival_4/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_sea_survival_4/npc_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_the_last_day_of_hiramakand/doodad_spawns.json create mode 100644 AAEmu.Game/Data/Worlds/instance_the_last_day_of_hiramakand/npc_spawns.json create mode 100644 AAEmu.Game/Models/Game/Auction/AuctionBid.cs create mode 100644 AAEmu.Game/Models/Game/Auction/AuctionDisplay.cs create mode 100644 AAEmu.Game/Models/Game/Auction/AuctionDuration.cs delete mode 100644 AAEmu.Game/Models/Game/Auction/AuctionItem.cs create mode 100644 AAEmu.Game/Models/Game/Auction/AuctionLot.cs create mode 100644 AAEmu.Game/Models/Game/Auction/AuctionSearch.cs create mode 100644 AAEmu.Game/Models/Game/Auction/AuctionSearchSortKind.cs create mode 100644 AAEmu.Game/Models/Game/Auction/AuctionSearchSortOrder.cs create mode 100644 AAEmu.Game/Models/Game/Auction/AuctionSold.cs delete mode 100644 AAEmu.Game/Models/Game/Auction/Templates/AuctionSearchTemplate.cs create mode 100644 AAEmu.Game/Models/Game/Items/Actions/ItemTaskLogType.cs create mode 100644 AAEmu.Game/Models/Game/Items/AuctionSettings.cs rename AAEmu.Game/Models/Game/Mails/{ => Static}/CommercialMailTypes.cs (77%) create mode 100644 AAEmu.Game/Models/Game/Mails/Static/MailBoxListKind.cs rename AAEmu.Game/Models/Game/Mails/{ => Static}/MailResult.cs (97%) rename AAEmu.Game/Models/Game/Mails/{ => Static}/MailStatus.cs (61%) rename AAEmu.Game/Models/Game/Mails/{ => Static}/MailType.cs (95%) rename AAEmu.Game/Models/Game/Mails/{ => Static}/MiaMailTypes.cs (65%) create mode 100644 AAEmu.Game/Models/Game/Mails/Static/SystemMailSenderKind.cs create mode 100644 AAEmu.Game/Models/Game/Schedules/ScheduleItems.cs create mode 100644 AAEmu.Game/Models/Game/Skills/Buffs/ManaRegenTemplate.cs create mode 100644 AAEmu.Game/Models/Game/Skills/Effects/MoveToLocationEffect.cs create mode 100644 SQL/patches/compact_server_table/loots_5070_add_memory-ember.sql create mode 100644 SQL/updates/2024-06-09_aaemu_game_divine_clock.sql create mode 100644 SQL/updates/2024-09-16_aaemu_game_item_containers_update.sql create mode 100644 SQL/updates/2024-09-16_aaemu_game_items_update.sql create mode 100644 SQL/updates/2024-10-04_aaemu_game_auction_house_update.sql create mode 100644 SQL/updates/2024-10-06_aaemu_game_auction_sold.sql create mode 100644 SQL/updates/2024-10-25_aaemu_game_auction_house_update.sql create mode 100644 SQL/updates/2024-10-28_aaemu_game_auction_solds_data_update.sql diff --git a/AAEmu.Commons/Cryptography/ConnectionKeychain.cs b/AAEmu.Commons/Cryptography/ConnectionKeychain.cs index 55a12bfd9e..fa1c770262 100644 --- a/AAEmu.Commons/Cryptography/ConnectionKeychain.cs +++ b/AAEmu.Commons/Cryptography/ConnectionKeychain.cs @@ -15,6 +15,8 @@ public class ConnectionKeychain public byte[] AesKey { get; set; } public byte[] IV { get; set; } public uint XorKey { get; set; } + public uint XorKeyConstant1 { get; set; } + public uint XorKeyConstant2 { get; set; } public byte SCMessageCount { get; set; } public byte CSMessageCount { get; set; } public byte CSOffsetSequence { get; set; } @@ -27,6 +29,8 @@ public ConnectionKeychain(uint connId, RSACryptoServiceProvider kp) AesKey = new byte[16]; IV = new byte[16]; XorKey = 0; + XorKeyConstant1 = 0; + XorKeyConstant2 = 0; } } } diff --git a/AAEmu.Commons/Cryptography/EncryptionManager.cs b/AAEmu.Commons/Cryptography/EncryptionManager.cs index 5e22495bc6..96104585ca 100644 --- a/AAEmu.Commons/Cryptography/EncryptionManager.cs +++ b/AAEmu.Commons/Cryptography/EncryptionManager.cs @@ -9,6 +9,7 @@ using System.Security.Cryptography; using System.Text; +using AAEmu.Commons.IO; using AAEmu.Commons.Network; using AAEmu.Commons.Utils; @@ -21,6 +22,11 @@ public class EncryptionManager : Singleton private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly int DwKeySize = 1024; private Dictionary ConnectionKeys { get; set; } //Dictionary of valid keys bound to account Id and connection Id + public static bool needNewkey2; + public static bool needNewkey1; + private static string XorKeyValueFilePath; + private static Random rnd = new(); + public void Load() { @@ -74,6 +80,33 @@ public void StoreClientKeys(byte[] aesKeyEncrypted, byte[] xorKeyEncrypted, ulon keys.AesKey = keys.RsaKeyPair.Decrypt(aesKeyEncrypted, false); keys.RecievedKeys = true; Logger.Warn("AES: {0} XOR: {1}", Helpers.ByteArrayToString(keys.AesKey), keys.XorKey); + + // для автоматического подбора констант + LoadXorKeyConstant(keys); + } + + private static void LoadXorKeyConstant(ConnectionKeychain keys) + { + var worldPath = Path.Combine(FileManager.AppPath, "Configurations"); + XorKeyValueFilePath = Path.Combine(worldPath, "xorKeyValue.txt"); + using var reader = new StreamReader(XorKeyValueFilePath); + while (!reader.EndOfStream) + { + var xorKeyValueLine1 = reader.ReadLine(); + var xorKeyValue1 = reader.ReadLine(); + if (xorKeyValueLine1 == "XorKeyConstant1:") + { + // сохраняем пакеты в список пакетов + keys.XorKeyConstant1 = Convert.ToUInt32(xorKeyValue1, 16); + } + var xorKeyValueLine2 = reader.ReadLine(); + var xorKeyValue2 = reader.ReadLine(); + if (xorKeyValueLine2 == "XorKeyConstant2:") + { + // сохраняем пакеты в список пакетов + keys.XorKeyConstant2 = Convert.ToUInt32(xorKeyValue2, 16); + } + } } public byte GetSCMessageCount(uint connectionId, ulong accountId) @@ -225,6 +258,62 @@ private static string ByteArrayToHexString(byte[] bytes) public static byte[] DecodeXor(byte[] bodyPacket, uint xorKey, ConnectionKeychain keys) { + /* + * логика подбора такая: + * сначала подбираем первую константу для имеющейся второй + * если первая 0xFF, то меняем вторую на новую и начинаем подбор первой константы с 0x00 + */ + var dirty = false; + // подбираем константы шифрации + if (keys.XorKeyConstant1 > 0x75A02480) + { + keys.XorKeyConstant1 = 0x75A02450; + dirty = true; + needNewkey2 = true; + } + if (keys.XorKeyConstant1 == 0 || keys.XorKeyConstant2 == 0) + { + LoadXorKeyConstant(keys); + + //keys.XorKeyConstant2 = 0x00a3af00; + //dirty = true; + //needNewkey2 = true; + } + + if (needNewkey1) + { + needNewkey1 = false; + // заменим первую константу + keys.XorKeyConstant1++; + if (keys.XorKeyConstant1 > 0x75A02480) + { + keys.XorKeyConstant1 = 0x75A02450; + needNewkey2 = true; + } + dirty = true; + } + if (needNewkey2) + { + needNewkey2 = false; + // заменим вторую константу + var tuneL = (byte)rnd.Next(0x01, 0xFF); + var tuneR = (byte)rnd.Next(0x01, 0xFF); + // Исходное uint число с заполнителями NN + var result = keys.XorKeyConstant2 & 0x00FFFF00; + result |= (uint)tuneL << 24; // Вставляем tuneL в старший байт + result |= tuneR; // Вставляем tuneR в младший байт + keys.XorKeyConstant2 = result; // Заменяем байты на указанные значения + dirty = true; + } + if (dirty) + { + using var writer = new StreamWriter(XorKeyValueFilePath, false); + writer.WriteLine("XorKeyConstant1:"); + writer.WriteLine(keys.XorKeyConstant1.ToString("X8")); + writer.WriteLine("XorKeyConstant2:"); + writer.WriteLine(keys.XorKeyConstant2.ToString("X8")); + } + // +-Hash начало блока для DecodeXOR, где второе число, в данном случае F(16 байт)-реальная длина данных в пакете, к примеру A(10 байт)-реальная длина данных в пакете // | +-начало блока для DecodeAES // V V @@ -251,8 +340,8 @@ public static byte[] DecodeXor(byte[] bodyPacket, uint xorKey, ConnectionKeychai //var cry = mul ^ ((uint)MakeSeq(keys) + 0x75a024a4) ^ 0xc3903b6a; // 3.0.3.0 archerage.to //var cry = mul ^ ((uint)MakeSeq(keys) + 0x75a024c4) ^ 0x2d3c9291; // 3.0.4.2 AAClassic //var cry = mul ^ ((uint)MakeSeq(keys) + 0x75a02403) ^ 0x47a3afc6; // 5.0.7.0 AAFree - работает, но плохо - var cry = mul ^ ((uint)MakeSeq(keys) + 0x75a02476) ^ 0x45a3af75; // 5.0.7.0 AAFree - работает, довольно хорошо - + var cry = mul ^ ((uint)MakeSeq(keys) + keys.XorKeyConstant1) ^ keys.XorKeyConstant2; // 5.0.7.0 AAFree - работает, довольно хорошо + var seq = keys.CSOffsetSequence; var offset = 4; if (seq != 0) diff --git a/AAEmu.Commons/Network/PacketStream.cs b/AAEmu.Commons/Network/PacketStream.cs index 83b14a5d2b..a7e0733edd 100644 --- a/AAEmu.Commons/Network/PacketStream.cs +++ b/AAEmu.Commons/Network/PacketStream.cs @@ -602,7 +602,6 @@ public long[] ReadPiscW(int hcount) return values; } - public (float x, float y, float z) ReadPosition() { var position = ReadBytes(9); diff --git a/AAEmu.Game/AAEmu.Game.csproj b/AAEmu.Game/AAEmu.Game.csproj index f816e9470d..dd9748b4c6 100644 --- a/AAEmu.Game/AAEmu.Game.csproj +++ b/AAEmu.Game/AAEmu.Game.csproj @@ -15,6 +15,9 @@ + + PreserveNewest + PreserveNewest @@ -59,6 +62,7 @@ + PreserveNewest diff --git a/AAEmu.Game/Configurations/xorKeyValue.txt b/AAEmu.Game/Configurations/xorKeyValue.txt new file mode 100644 index 0000000000..ef2621a22a --- /dev/null +++ b/AAEmu.Game/Configurations/xorKeyValue.txt @@ -0,0 +1,4 @@ +XorKeyConstant1: +75A0247F +XorKeyConstant2: +E7A3AF60 diff --git a/AAEmu.Game/Core/Managers/AccountManager.cs b/AAEmu.Game/Core/Managers/AccountManager.cs index 5aaf49eb8a..881b21d393 100644 --- a/AAEmu.Game/Core/Managers/AccountManager.cs +++ b/AAEmu.Game/Core/Managers/AccountManager.cs @@ -8,6 +8,7 @@ using AAEmu.Game.Core.Network.Connections; using AAEmu.Game.Models; using AAEmu.Game.Models.Account; +using AAEmu.Game.Models.Game; using NLog; @@ -36,6 +37,13 @@ public void Add(GameConnection connection) _accounts.TryAdd(connection.AccountId, connection); var lastLogin = UpdateLoginTime(connection.AccountId, DateTime.UtcNow); var accountDetails = GetAccountDetails(connection.AccountId); + + var lsi = GetDivineClock(connection.AccountId); + if (lsi?.Count == 0) + { + TimedRewardsManager.Instance.DoDailyAccountDivineClockLogin(connection.AccountId); + } + if (lastLogin < DateTime.UtcNow.Date) { // Logged in for a new day @@ -360,10 +368,11 @@ public void UpdateDivineClock(ulong accountId, uint timeElapsed, uint timesTaken { using var connection = MySQL.CreateConnection(); using var command = connection.CreateCommand(); - command.CommandText = "UPDATE accounts SET divine_clock_time = @divine_clock_time , divine_clock_taken = @divine_clock_taken WHERE account_id = @account_id"; + command.CommandText = "UPDATE accounts SET cumulated = @cumulated , gave = @gave" + + " WHERE account_id = @account_id"; command.Parameters.AddWithValue("@account_id", accountId); - command.Parameters.AddWithValue("@divine_clock_time", timeElapsed); - command.Parameters.AddWithValue("@divine_clock_taken", timesTaken); + command.Parameters.AddWithValue("@cumulated", timeElapsed); + command.Parameters.AddWithValue("@gave", timesTaken); command.Prepare(); command.ExecuteNonQuery(); } @@ -374,12 +383,53 @@ public void UpdateDivineClock(ulong accountId, uint timeElapsed, uint timesTaken } } + public void UpdateDivineClock(ulong accountId, uint scheduleItemId, uint timeElapsed, uint timesTaken) + { + object accLock; + lock (_locks) + { + if (!_locks.TryGetValue(accountId, out accLock)) + { + accLock = new object(); + _locks.Add(accountId, accLock); + } + } + lock (accLock) + { + try + { + using var connection = MySQL.CreateConnection(); + using var command = connection.CreateCommand(); + command.CommandText = "UPDATE divine_clock SET cumulated = @cumulated, gave = @gave" + + " WHERE account_id = @account_id AND schedule_item_id = @schedule_item_id"; + command.Parameters.AddWithValue("@account_id", accountId); + command.Parameters.AddWithValue("@schedule_item_id", scheduleItemId); + command.Parameters.AddWithValue("@cumulated", timeElapsed); + command.Parameters.AddWithValue("@gave", timesTaken); + command.Prepare(); + var rowsAffected = command.ExecuteNonQuery(); + + // If no rows were updated, insert a new record + if (rowsAffected == 0) + { + command.CommandText = "INSERT INTO divine_clock (account_id, schedule_item_id, cumulated, gave)" + + "VALUES (@account_id, @schedule_item_id, @cumulated, @gave)"; + command.ExecuteNonQuery(); + } + } + catch (Exception e) + { + Logger.Error($"{e.Message}\n{e.StackTrace}"); + } + } + } + /// /// Returns the divine_clock_time and divine_clock_taken values for given account /// /// /// - public (uint, uint) GetDivineClock(ulong accountId) + public (uint, uint) GetDivineClock2(ulong accountId) { var timeElapsed = 0u; var timesTaken = 0u; @@ -417,4 +467,160 @@ public void UpdateDivineClock(ulong accountId, uint timeElapsed, uint timesTaken return (timeElapsed, timesTaken); } + + public (uint TimeElapsed, uint TimesTaken) GetDivineClock2(ulong accountId, uint scheduleItemId) + { + var timeElapsed = 0u; + var timesTaken = 0u; + object accLock; + lock (_locks) + { + if (!_locks.TryGetValue(accountId, out accLock)) + { + accLock = new object(); + _locks.Add(accountId, accLock); + } + } + lock (accLock) + { + try + { + using var connection = MySQL.CreateConnection(); + using var command = connection.CreateCommand(); + command.CommandText = "SELECT cumulated, gave FROM divine_clock WHERE account_id = @account_id AND schedule_item_id = @schedule_item_id"; + command.Parameters.AddWithValue("@account_id", accountId); + command.Parameters.AddWithValue("@schedule_item_id", scheduleItemId); + command.Prepare(); + using var reader = command.ExecuteReader(); + if (reader.Read()) + { + timeElapsed = reader.GetUInt32("cumulated"); + timesTaken = reader.GetUInt32("gave"); + } + reader.Close(); + } + catch (Exception e) + { + Logger.Error($"{e.Message}\n{e.StackTrace}"); + } + } + + return (timeElapsed, timesTaken); + } + + public ScheduleItem GetDivineClock(ulong accountId, uint scheduleItemId) + { + var scheduleItem = new ScheduleItem(); + scheduleItem.ScheduleItemId = scheduleItemId; + object accLock; + lock (_locks) + { + if (!_locks.TryGetValue(accountId, out accLock)) + { + accLock = new object(); + _locks.Add(accountId, accLock); + } + } + lock (accLock) + { + try + { + using var connection = MySQL.CreateConnection(); + using var command = connection.CreateCommand(); + command.CommandText = "SELECT cumulated, gave FROM divine_clock WHERE account_id = @account_id AND schedule_item_id = @schedule_item_id"; + command.Parameters.AddWithValue("@account_id", accountId); + command.Parameters.AddWithValue("@schedule_item_id", scheduleItemId); + command.Prepare(); + using var reader = command.ExecuteReader(); + if (reader.Read()) + { + scheduleItem.Cumulated = reader.GetUInt32("cumulated"); + scheduleItem.Gave = reader.GetByte("gave"); + } + reader.Close(); + } + catch (Exception e) + { + Logger.Error($"{e.Message}\n{e.StackTrace}"); + return null; // Возвращаем null в случае ошибки + } + } + + return scheduleItem; + } + public List GetDivineClock(ulong accountId) + { + var scheduleItems = new List(); + object accLock; + lock (_locks) + { + if (!_locks.TryGetValue(accountId, out accLock)) + { + accLock = new object(); + _locks.Add(accountId, accLock); + } + } + lock (accLock) + { + try + { + using var connection = MySQL.CreateConnection(); + using var command = connection.CreateCommand(); + command.CommandText = "SELECT * FROM divine_clock WHERE account_id = @account_id"; + command.Parameters.AddWithValue("@account_id", accountId); + command.Prepare(); + + using var reader = command.ExecuteReader(); + while (reader.Read()) + { + var scheduleItem = new ScheduleItem + { + ScheduleItemId = reader.GetUInt32("schedule_item_id"), + Cumulated = reader.GetUInt32("cumulated"), + Gave = reader.GetByte("gave") + }; + scheduleItems.Add(scheduleItem); + } + } + catch (Exception e) + { + Logger.Error($"{e.Message}\n{e.StackTrace}"); + return null; // Возвращаем null в случае ошибки + } + } + + return scheduleItems; + } + + public bool DeleteDivineClockEntries(ulong accountId) + { + object accLock; + lock (_locks) + { + if (!_locks.TryGetValue(accountId, out accLock)) + { + accLock = new object(); + _locks.Add(accountId, accLock); + } + } + lock (accLock) + { + try + { + using var connection = MySQL.CreateConnection(); + using var command = connection.CreateCommand(); + command.CommandText = "DELETE FROM divine_clock WHERE account_id = @account_id"; + command.Parameters.AddWithValue("@account_id", accountId); + command.Prepare(); + + int rowsAffected = command.ExecuteNonQuery(); + return rowsAffected > 0; // Возвращаем true, если были удалены записи + } + catch (Exception e) + { + Logger.Error($"{e.Message}\n{e.StackTrace}"); + return false; // Возвращаем false в случае ошибки + } + } + } } diff --git a/AAEmu.Game/Core/Managers/AuctionManager.cs b/AAEmu.Game/Core/Managers/AuctionManager.cs index a76a07ee43..7f759fa5d0 100644 --- a/AAEmu.Game/Core/Managers/AuctionManager.cs +++ b/AAEmu.Game/Core/Managers/AuctionManager.cs @@ -2,14 +2,16 @@ using System.Collections.Generic; using System.Linq; +using AAEmu.Commons.Network; using AAEmu.Commons.Utils; using AAEmu.Commons.Utils.DB; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Auction; -using AAEmu.Game.Models.Game.Auction.Templates; using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Items; +using AAEmu.Game.Models.Game.Items.Actions; using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Scripts.Commands; using MySql.Data.MySqlClient; @@ -21,43 +23,20 @@ public class AuctionManager : Singleton { private static Logger Logger { get; } = LogManager.GetCurrentClassLogger(); - public List _auctionItems; + public List AuctionLots; + public Dictionary<(uint TemplateId, byte Grade), List<(DateTime Date, AuctionLot Lot)>> SalesData = new(); + public Dictionary<(uint TemplateId, byte Grade), List<(DateTime Date, AuctionSold Sold)>> SoldsData = new(); + public List _deletedAuctionItemIds; - private static int MaxListingFee = 1000000; // 100g + private static int MaxListingFee = 1000000; // 100g, 100 copper coins = 1 silver, 100 silver = 1 gold. - public void ListAuctionItem(Character player, ulong itemId, int startPrice, int buyoutPrice, byte duration) + private void RemoveAuctionLotSold(AuctionLot itemToRemove, string buyer, int soldAmount) { - var newItem = player.Inventory.GetItemById(itemId); - var newAuctionItem = CreateAuctionItem(player, newItem, startPrice, buyoutPrice, duration); - - if (newAuctionItem == null) //TODO - return; - - if (newItem == null) //TODO - return; - - var auctionFee = (newAuctionItem.DirectMoney * .01) * (duration + 1); - - if (auctionFee > MaxListingFee) - auctionFee = MaxListingFee; - - if (!player.ChangeMoney(SlotType.Inventory, -(int)auctionFee)) + if (AuctionLots.Contains(itemToRemove)) { - player.SendErrorMessage(ErrorMessageType.CanNotPutupMoney); - return; - } - player.Inventory.Bag.RemoveItem(Models.Game.Items.Actions.ItemTaskType.Auction, newItem, true); - AddAuctionItem(newAuctionItem); - player.SendPacket(new SCAuctionPostedPacket(newAuctionItem)); - } + var newItem = ItemManager.Instance.GetItemByItemId(itemToRemove.Item.Id); - private void RemoveAuctionItemSold(AuctionItem itemToRemove, string buyer, int soldAmount) - { - if (_auctionItems.Contains(itemToRemove)) - { - var itemTemplate = ItemManager.Instance.GetItemTemplateFromItemId(itemToRemove.ItemId); - var newItem = ItemManager.Instance.Create(itemTemplate.Id, (int)itemToRemove.StackSize, itemToRemove.Grade); var itemList = new Item[10].ToList(); itemList[0] = newItem; @@ -66,7 +45,7 @@ private void RemoveAuctionItemSold(AuctionItem itemToRemove, string buyer, int s moneyToSend[0] = (int)moneyAfterFee; // TODO: Read this from saved data - var recalculatedFee = (itemToRemove.DirectMoney * .01) * (itemToRemove.Duration + 1); + var recalculatedFee = itemToRemove.DirectMoney * .01 * ((int)itemToRemove.Duration - 8 + 1); if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; if (itemToRemove.ClientName != "") @@ -81,215 +60,264 @@ private void RemoveAuctionItemSold(AuctionItem itemToRemove, string buyer, int s buyMail.FinalizeForSaleBuyer(buyerId); buyMail.Send(); - RemoveAuctionItem(itemToRemove); + RemoveAuctionLot(itemToRemove); + } + } + + private void BuyPartOfTheAuctionLot(AuctionLot auctionLot, string buyer, int soldAmount, int count) + { + // предмет должен быть с новым id + var itemTemplate = ItemManager.Instance.GetItemTemplateFromItemId(auctionLot.Item.TemplateId); + var newItem = ItemManager.Instance.Create(itemTemplate.Id, count, auctionLot.Item.Grade); + + var moneyAfterFee = soldAmount * .9; + + // TODO: Read this from saved data + var recalculatedFee = auctionLot.DirectMoney * .01 * ((int)auctionLot.Duration - 8 + 1); + if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; + + if (auctionLot.ClientName != "") + { + // Хозяину отсылаем часть денег за покупку + var sellMail = new MailForAuction(newItem, auctionLot.ClientId, soldAmount, (int)recalculatedFee); + sellMail.FinalizeForSaleSeller((int)moneyAfterFee, (int)(soldAmount - moneyAfterFee)); + sellMail.Send(); } + + // Покупателю отсылаем купленный лот + var buyMail = new MailForAuction(newItem, auctionLot.ClientId, soldAmount, (int)recalculatedFee); + var buyerId = NameManager.Instance.GetCharacterId(buyer); + buyMail.FinalizeForSaleBuyer(buyerId); + buyMail.Send(); + + RemoveAuctionLot(auctionLot); } - private void RemoveAuctionItemFail(AuctionItem itemToRemove) + private void RemoveAuctionLotFail(AuctionLot itemToRemove) { - if (!_auctionItems.Contains(itemToRemove)) + if (!AuctionLots.Contains(itemToRemove)) return; - if (itemToRemove.BidderName != "") //Player won the bid. + if (itemToRemove.BidderName != "") // Player won the bid. { - RemoveAuctionItemSold(itemToRemove, itemToRemove.BidderName, itemToRemove.BidMoney); + RemoveAuctionLotSold(itemToRemove, itemToRemove.BidderName, itemToRemove.BidMoney); return; } - else //Item did not sell by end of the timer. - { - var itemTemplate = ItemManager.Instance.GetItemTemplateFromItemId(itemToRemove.ItemId); - var newItem = ItemManager.Instance.Create(itemTemplate.Id, (int)itemToRemove.StackSize, itemToRemove.Grade); - var itemList = new Item[10].ToList(); - itemList[0] = newItem; - // TODO: Read this from saved data - var recalculatedFee = (itemToRemove.DirectMoney * .01) * (itemToRemove.Duration + 1); - if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; + // Item did not sell by end of the timer. + var newItem = ItemManager.Instance.GetItemByItemId(itemToRemove.Item.Id); + var itemList = new Item[10].ToList(); + itemList[0] = newItem; - if (itemToRemove.ClientName != "") - { - var failMail = new MailForAuction(newItem, itemToRemove.ClientId, itemToRemove.DirectMoney, (int)recalculatedFee); - failMail.FinalizeForFail(); - failMail.Send(); - } + // TODO: Read this from saved data + var recalculatedFee = itemToRemove.DirectMoney * .01 * ((int)itemToRemove.Duration - 8 + 1); + if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; - RemoveAuctionItem(itemToRemove); + if (itemToRemove.ClientName != "") + { + var failMail = new MailForAuction(newItem, itemToRemove.ClientId, itemToRemove.DirectMoney, (int)recalculatedFee); + failMail.FinalizeForFail(); + failMail.Send(); } + + RemoveAuctionLot(itemToRemove); } - public void CancelAuctionItem(Character player, ulong auctionId) + public void CancelAuctionLot(Character player, ulong auctionId) { - var auctionItem = GetAuctionItemFromID(auctionId); + var auctionItem = GetAuctionLotFromId(auctionId); if (auctionItem.BidderName != "") return;// Someone has already bid on the item and we do not want to remove it. var moneyToSubtract = auctionItem.DirectMoney * .1f; var itemList = new Item[10].ToList(); - var newItem = ItemManager.Instance.Create(auctionItem.ItemId, (int)auctionItem.StackSize, auctionItem.Grade); + var newItem = ItemManager.Instance.Create(auctionItem.Item.TemplateId, auctionItem.Item.Count, auctionItem.Item.Grade); itemList[0] = newItem; // TODO: Read this from saved data - var recalculatedFee = (auctionItem.DirectMoney * .01) * (auctionItem.Duration + 1); + var recalculatedFee = auctionItem.DirectMoney * .01 * ((int)auctionItem.Duration - 8 + 1); if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; var cancelMail = new MailForAuction(newItem, auctionItem.ClientId, auctionItem.DirectMoney, (int)recalculatedFee); cancelMail.FinalizeForCancel(); cancelMail.Send(); - // MailManager.Instance.SendMail(0, auctionItem.ClientName, "AuctionHouse", "Cancelled Listing", "See attaached.", 1, new int[3], 0, itemList); + //MailManager.Instance.SendMail(0, auctionItem.ClientName, "AuctionHouse", "Cancelled Listing", "See attached.", 1, new int[3], 0, itemList); - RemoveAuctionItem(auctionItem); + RemoveAuctionLot(auctionItem); player.SendPacket(new SCAuctionCanceledPacket(auctionItem)); } - private AuctionItem GetAuctionItemFromID(ulong auctionId) + private AuctionLot GetAuctionLotFromId(ulong auctionId) { - var item = _auctionItems.Single(c => c.Id == auctionId); + var lot = AuctionLots.Single(c => c.Id == auctionId); - return item; + return lot; } - public void BidOnAuctionItem(Character player, ulong auctionId, int bidAmount) + + public void BidOnAuctionLot(Character player, uint auctioneerId, uint auctioneerId2, AuctionLot lot, AuctionBid bid) { - var auctionItem = GetAuctionItemFromID(auctionId); - if (auctionItem != null) + if (player == null || lot == null || bid == null) + { + // Логирование или обработка ошибки + Logger.Warn("Invalid arguments passed to BidOnAuctionLot."); + return; + } + + //var auctionItem = GetAuctionLotFromId(lot.Id); + var auctionLot = lot; + if (auctionLot != null) { - if (bidAmount >= auctionItem.DirectMoney && auctionItem.DirectMoney != 0) //Buy now + // TODO сравним, что прислал клиент и что есть на сервере + // auctionItem == lot ? + + if (bid.StackSize != 0 && bid.StackSize >= auctionLot.MinStack && bid.StackSize <= auctionLot.MaxStack && auctionLot.BidderId == 0) // Buy part of the lot + { + BuyPartOfTheAuctionLot(auctionLot, player.Name, bid.Money, bid.StackSize); + + // Set info to new bidders info + auctionLot.Item.Count -= bid.StackSize; + + bid.BidderName = player.Name; + bid.BidderId = player.Id; + bid.WorldId = (byte)player.Transform.WorldId; + + player.SubtractMoney(SlotType.Bag, bid.Money); + player.SendPacket(new SCAuctionBidPacket(bid, false, auctionLot.Item.TemplateId)); + auctionLot.IsDirty = true; + + // Обновление данных в списке AuctionLots + UpdateAuctionLotInList(auctionLot); + + auctionLot.BidMoney = bid.Money; + auctionLot.Extra = bid.StackSize; + } + else if (bid.Money >= auctionLot.DirectMoney && auctionLot.DirectMoney != 0) // Buy now { - if (auctionItem.BidderId != 0) // send mail to person who bid if item was bought at full price. + if (auctionLot.BidderId != 0) // send mail to person who bid if item was bought at full price. { - var newMail = new MailForAuction(auctionItem.ItemId, auctionItem.ClientId, auctionItem.DirectMoney, 0); - newMail.FinalizeForBidFail(auctionItem.BidderId, auctionItem.BidMoney); + var newMail = new MailForAuction(auctionLot.Item.TemplateId, auctionLot.ClientId, auctionLot.DirectMoney, 0); + newMail.FinalizeForBidFail(auctionLot.BidderId, auctionLot.BidMoney); newMail.Send(); } - player.SubtractMoney(SlotType.Inventory, auctionItem.DirectMoney); - RemoveAuctionItemSold(auctionItem, player.Name, auctionItem.DirectMoney); - } + player.SubtractMoney(SlotType.Bag, auctionLot.DirectMoney); + RemoveAuctionLotSold(auctionLot, player.Name, auctionLot.DirectMoney); - else if (bidAmount > auctionItem.BidMoney) //Bid + auctionLot.BidMoney = bid.Money; + auctionLot.Extra = bid.StackSize; + } + else if (bid.Money > auctionLot.BidMoney) // Bid { - if ((auctionItem.BidderName != "") && (auctionItem.BidderId != 0)) //Send mail to old bidder. + if (auctionLot.BidderName != "" && auctionLot.BidderId != 0) // Send mail to old bidder. { var moneyArray = new int[3]; - moneyArray[0] = auctionItem.BidMoney; + moneyArray[0] = auctionLot.BidMoney; // TODO: Read this from saved data - var recalculatedFee = (auctionItem.DirectMoney * .01) * (auctionItem.Duration + 1); + var recalculatedFee = auctionLot.DirectMoney * .01 * ((int)auctionLot.Duration - 8 + 1); if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; - var cancelMail = new MailForAuction(auctionItem.ItemId, auctionItem.ClientId, auctionItem.DirectMoney, (int)recalculatedFee); - cancelMail.FinalizeForBidFail(auctionItem.BidderId, auctionItem.BidMoney); + var cancelMail = new MailForAuction(auctionLot.Item.TemplateId, auctionLot.ClientId, auctionLot.DirectMoney, (int)recalculatedFee); + cancelMail.FinalizeForBidFail(auctionLot.BidderId, auctionLot.BidMoney); cancelMail.Send(); } - //Set info to new bidders info - auctionItem.BidderName = player.Name; - auctionItem.BidderId = player.Id; - auctionItem.BidWorldId = (byte)player.Transform.WorldId; - auctionItem.BidMoney = bidAmount; - - player.SubtractMoney(SlotType.Inventory, bidAmount); - player.SendPacket(new SCAuctionBidPacket(auctionItem)); - auctionItem.IsDirty = true; - } - } - } + // Set info to new bidders info + auctionLot.BidderName = player.Name; + auctionLot.BidderId = player.Id; + auctionLot.BidWorldId = (byte)player.Transform.WorldId; + auctionLot.BidMoney = bid.Money; - public List GetAuctionItems(AuctionSearchTemplate searchTemplate) - { - List auctionItemsFound = new List(); - bool myListing = false; + bid.BidderName = player.Name; + bid.BidderId = player.Id; + bid.WorldId = (byte)player.Transform.WorldId; - if (searchTemplate.ItemName == "" && searchTemplate.CategoryA == 0 && searchTemplate.CategoryB == 0 && searchTemplate.CategoryC == 0) - { - myListing = true; - auctionItemsFound = _auctionItems.Where(c => c.ClientId == searchTemplate.PlayerId).ToList(); - } + player.SubtractMoney(SlotType.Bag, bid.Money, ItemTaskType.Auction); + player.SendPacket(new SCAuctionBidPacket(bid, false, auctionLot.Item.TemplateId)); + auctionLot.IsDirty = true; - if (!myListing) - { - var itemTemplateList = ItemManager.Instance.GetAllItems(); - var query = from item in itemTemplateList - where ((searchTemplate.ItemName != "") ? item.searchString.Contains(searchTemplate.ItemName.ToLower()) : true) - where ((searchTemplate.CategoryA != 0) ? searchTemplate.CategoryA == item.AuctionCategoryA : true) - where ((searchTemplate.CategoryB != 0) ? searchTemplate.CategoryB == item.AuctionCategoryB : true) - where ((searchTemplate.CategoryC != 0) ? searchTemplate.CategoryC == item.AuctionCategoryC : true) - select item; + // Обновление данных в списке AuctionLots + UpdateAuctionLotInList(auctionLot); - var selectedItemList = query.ToList(); + auctionLot.BidMoney = bid.Money; + auctionLot.Extra = bid.StackSize; + } - auctionItemsFound = _auctionItems.Where(c => selectedItemList.Any(c2 => c2.Id == c.ItemId)).ToList(); + AddAuctionSold(auctionLot); } + } - if (searchTemplate.SortKind == 1) //Price + public void UpdateAuctionLotInList(AuctionLot auctionLot) + { + if (auctionLot == null) { - var sortedList = auctionItemsFound.OrderByDescending(x => x.DirectMoney).ToList(); - auctionItemsFound = sortedList; - if (searchTemplate.SortOrder == 1) - auctionItemsFound.Reverse(); + // Логирование или обработка ошибки + Logger.Warn("Invalid auctionItem passed to UpdateAuctionLotInList."); + return; } - //TODO 2 Name of item - //TODO 3 Level of item - - if (searchTemplate.SortKind == 4) //TimeLeft + lock (AuctionLots) { - var sortedList = auctionItemsFound.OrderByDescending(x => x.TimeLeft).ToList(); - auctionItemsFound = sortedList; - if (searchTemplate.SortOrder == 1) - auctionItemsFound.Reverse(); - } + // Поиск лота в списке по идентификатору + var existingLot = AuctionLots.FirstOrDefault(lot => lot.Id == auctionLot.Id); - if (searchTemplate.Page > 0) - { - var startingItemNumber = (int)(searchTemplate.Page * 9); - var endingitemNumber = (int)((searchTemplate.Page * 9) + 9); - if (auctionItemsFound.Count > startingItemNumber) + if (existingLot != null) { - var tempItemList = new List(); - for (var i = startingItemNumber; i < endingitemNumber; i++) - { - if (auctionItemsFound.ElementAtOrDefault(i) != null) - tempItemList.Add(auctionItemsFound[i]); - } - auctionItemsFound = tempItemList; + // Обновление данных лота + existingLot.BidderName = auctionLot.BidderName; + existingLot.BidderId = auctionLot.BidderId; + existingLot.BidWorldId = auctionLot.BidWorldId; + existingLot.BidMoney = auctionLot.BidMoney; + existingLot.Item.Count = auctionLot.Item.Count; + existingLot.IsDirty = auctionLot.IsDirty; } else - searchTemplate.Page = 0; - } - - if (auctionItemsFound.Count > 9) - { - var tempList = new List(); - - for (int i = 0; i < 9; i++) { - tempList.Add(auctionItemsFound[i]); + // Логирование или обработка ошибки, если лот не найден + Logger.Warn($"AuctionLot with ID {auctionLot.Id} not found in the list."); } - - auctionItemsFound = tempList; } - return auctionItemsFound; } - public AuctionItem GetCheapestAuctionItem(ulong itemId) + public void GetBidAuctionLots(Character player, int page) { - var tempList = new List(); + var searchedArticles = AuctionLots.Where(lot => lot.BidderId == player.Id).ToList(); - foreach (var item in _auctionItems) + if (searchedArticles.Count <= 0) { - if (item.ItemId == itemId) - tempList.Add(item); + player.SendPacket(new SCAuctionSearchedPacket(0, 0, [], (short)ErrorMessageType.NoErrorMessage, DateTime.UtcNow)); + return; } - if (tempList.Count > 0) + var articles = SortArticles(searchedArticles, AuctionSearchSortKind.Default, AuctionSearchSortOrder.Asc).ToArray(); + var dividedLists = Helpers.SplitArray(articles, 9); // Разделяем массив на массивы по 9 значений + player.SendPacket(new SCAuctionSearchedPacket(page, dividedLists[page].Length, dividedLists[page].ToList(), (short)ErrorMessageType.NoErrorMessage, DateTime.UtcNow)); + } + + public AuctionLot GetCheapestAuctionLot(uint templateId) + { + var tempList = AuctionLots.Where(lot => lot.Item.TemplateId == templateId).ToList(); + + if (tempList.Count <= 0) { - tempList = tempList.OrderByDescending(x => x.DirectMoney).ToList(); - return tempList.First(); + return null; } - else + + tempList = tempList.OrderBy(x => x.DirectMoney).ToList(); + + return tempList.First(); + } + + public void CheapestAuctionLot(Character player, uint templateId, byte itemGrade = 0) + { + var DirectMoney = 0; + var cheapestItem = GetCheapestAuctionLot(templateId); + if (cheapestItem != null) { - return null; + DirectMoney = cheapestItem.DirectMoney; } + + player.SendPacket(new SCAuctionLowestPricePacket(templateId, itemGrade, DirectMoney)); } public static string GetLocalizedItemNameById(uint id) @@ -300,7 +328,7 @@ public static string GetLocalizedItemNameById(uint id) public ulong GetNextId() { ulong nextId = 0; - foreach (var item in _auctionItems) + foreach (var item in AuctionLots) { if (nextId < item.Id) nextId = item.Id; @@ -308,155 +336,157 @@ public ulong GetNextId() return nextId + 1; } - public void RemoveAuctionItem(AuctionItem itemToRemove) + public void RemoveAuctionLot(AuctionLot itemToRemove) { - if (itemToRemove.ClientName == "") //Testing feature. Relists an item if the server listed it. - { - itemToRemove.EndTime = DateTime.UtcNow.AddHours(48); - return; - } - lock (_auctionItems) + //if (itemToRemove.ClientName == "") // Testing feature. Relists an item if the server listed it. + //{ + // itemToRemove.EndTime = DateTime.UtcNow.AddHours(48); + // return; + //} + lock (AuctionLots) { lock (_deletedAuctionItemIds) { - if (_auctionItems.Contains(itemToRemove)) + if (AuctionLots.Contains(itemToRemove)) { _deletedAuctionItemIds.Add((long)itemToRemove.Id); - _auctionItems.Remove(itemToRemove); + AuctionLots.Remove(itemToRemove); } } } } - public void AddAuctionItem(AuctionItem itemToAdd) + public void AddAuctionLot(AuctionLot lot) { - lock (_auctionItems) + lock (AuctionLots) { - _auctionItems.Add(itemToAdd); + AuctionLots.Add(lot); } } public void UpdateAuctionHouse() { Logger.Trace("Updating Auction House!"); - lock (_auctionItems) + lock (AuctionLots) { - var itemsToRemove = _auctionItems.Where(c => DateTime.UtcNow > c.EndTime); + var itemsToRemove = AuctionLots.Where(c => DateTime.UtcNow > c.EndTime); foreach (var item in itemsToRemove) { if (item.BidderId != 0) - RemoveAuctionItemSold(item, item.BidderName, item.BidMoney); + RemoveAuctionLotSold(item, item.BidderName, item.BidMoney); else - RemoveAuctionItemFail(item); + RemoveAuctionLotFail(item); } } } - public AuctionItem CreateAuctionItem(Character player, Item itemToList, int startPrice, int buyoutPrice, byte duration) + public AuctionLot CreateAuctionLot(Character player, Item itemToList, int startPrice, int buyoutPrice, AuctionDuration duration, int minStack, int maxStack) { - var newItem = itemToList; - ulong timeLeft; switch (duration) { - case 0: - timeLeft = 6; //6 hours + case AuctionDuration.AuctionDuration6Hours: + timeLeft = 6; // 6 hours break; - case 1: - timeLeft = 12; //12 hours + case AuctionDuration.AuctionDuration12Hours: + timeLeft = 12; // 12 hours break; - case 2: - timeLeft = 24; //24 hours + case AuctionDuration.AuctionDuration24Hours: + timeLeft = 24; // 24 hours break; - case 3: - timeLeft = 48; //48 hours + case AuctionDuration.AuctionDuration48Hours: + timeLeft = 48; // 48 hours break; default: - timeLeft = 6; //default to 6 hours + timeLeft = 6; // default to 6 hours break; } - var newAuctionItem = new AuctionItem - { - Id = GetNextId(), - Duration = 5, - ItemId = newItem.Template.Id, - ObjectId = 0, - Grade = newItem.Grade, - Flags = newItem.ItemFlags, - StackSize = (uint)newItem.Count, - DetailType = 0, - CreationTime = DateTime.UtcNow, - EndTime = DateTime.UtcNow.AddHours(timeLeft), - LifespanMins = 0, - Type1 = 0, - WorldId = 0, - UnpackDateTime = DateTime.UtcNow, - UnsecureDateTime = DateTime.UtcNow, - WorldId2 = 0, - ClientId = player.Id, - ClientName = player.Name, - StartMoney = startPrice, - DirectMoney = buyoutPrice, - BidWorldId = 0, - BidderId = 0, - BidderName = "", - BidMoney = 0, - Extra = 0, - IsDirty = true - }; - return newAuctionItem; + var newAuctionLot = new AuctionLot(); + newAuctionLot.Id = GetNextId(); + newAuctionLot.Duration = duration; + + newAuctionLot.Item = itemToList; + + newAuctionLot.EndTime = DateTime.UtcNow.AddHours(timeLeft); + + newAuctionLot.WorldId = 1; + newAuctionLot.ClientId = player.Id; + newAuctionLot.ClientName = player.Name; + newAuctionLot.StartMoney = startPrice; + newAuctionLot.DirectMoney = buyoutPrice; + newAuctionLot.PostDate = DateTime.UtcNow; + newAuctionLot.ChargePercent = 1000; // added in 5+ + newAuctionLot.BidWorldId = 255; + newAuctionLot.BidderId = 0; + newAuctionLot.BidderName = ""; + newAuctionLot.BidMoney = 0; + newAuctionLot.Extra = 0; + newAuctionLot.MinStack = minStack; // added in 5+ + newAuctionLot.MaxStack = maxStack; // added in 5+ + newAuctionLot.IsDirty = true; + + return newAuctionLot; } public void Load() { - _auctionItems = new List(); - _deletedAuctionItemIds = new List(); + AuctionLots = []; + SoldsData = []; + _deletedAuctionItemIds = []; + using (var connection = MySQL.CreateConnection()) { using (var command = connection.CreateCommand()) { - command.CommandText = $"SELECT * FROM auction_house"; + command.CommandText = "SELECT * FROM auction_house"; command.Prepare(); using (var reader = command.ExecuteReader()) { while (reader.Read()) { - var auctionItem = new AuctionItem(); - auctionItem.Id = reader.GetUInt32("id"); - auctionItem.Duration = reader.GetByte("duration"); //0 is 6 hours, 1 is 12 hours, 2 is 24 hours, 3 is 48 hours - auctionItem.ItemId = reader.GetUInt32("item_id"); - auctionItem.ObjectId = reader.GetUInt32("object_id"); - auctionItem.Grade = reader.GetByte("grade"); - auctionItem.Flags = (ItemFlag)reader.GetByte("flags"); - auctionItem.StackSize = reader.GetUInt32("stack_size"); - auctionItem.DetailType = reader.GetByte("detail_type"); - auctionItem.CreationTime = reader.GetDateTime("creation_time"); - auctionItem.EndTime = reader.GetDateTime("end_time"); - auctionItem.LifespanMins = reader.GetUInt32("lifespan_mins"); - auctionItem.Type1 = reader.GetUInt32("type_1"); - auctionItem.WorldId = reader.GetByte("world_id"); - auctionItem.UnsecureDateTime = reader.GetDateTime("unsecure_date_time"); - auctionItem.UnpackDateTime = reader.GetDateTime("unpack_date_time"); - auctionItem.WorldId2 = reader.GetByte("world_id_2"); - auctionItem.ClientId = reader.GetUInt32("client_id"); - auctionItem.ClientName = reader.GetString("client_name"); - auctionItem.StartMoney = reader.GetInt32("start_money"); - auctionItem.DirectMoney = reader.GetInt32("direct_money"); - auctionItem.BidWorldId = reader.GetByte("bid_world_id"); - auctionItem.BidderId = reader.GetUInt32("bidder_id"); - auctionItem.BidderName = reader.GetString("bidder_name"); - auctionItem.BidMoney = reader.GetInt32("bid_money"); - auctionItem.Extra = reader.GetUInt32("extra"); - AddAuctionItem(auctionItem); + var auctionLot = new AuctionLot(); + auctionLot.Id = reader.GetUInt64("id"); + auctionLot.Duration = (AuctionDuration)reader.GetByte("duration"); // 8 is 6 hours, 9 is 12 hours, 10 is 24 hours, 11 is 48 hours + + var itemId = reader.GetUInt32("item_id"); + var item = ItemManager.Instance.GetItemByItemId(itemId); + if (item == null) + { + continue; + } + + auctionLot.EndTime = reader.GetDateTime("end_time"); + + auctionLot.WorldId = reader.GetByte("world_id"); + auctionLot.ClientId = reader.GetUInt32("client_id"); + auctionLot.ClientName = reader.GetString("client_name"); + auctionLot.StartMoney = reader.GetInt32("start_money"); + auctionLot.DirectMoney = reader.GetInt32("direct_money"); + + auctionLot.ChargePercent = reader.GetInt32("charge_percent"); // added in 5+ + + auctionLot.BidWorldId = (byte)reader.GetInt32("bid_world_id"); + auctionLot.BidderId = reader.GetUInt32("bidder_id"); + auctionLot.BidderName = reader.GetString("bidder_name"); + auctionLot.BidMoney = reader.GetInt32("bid_money"); + auctionLot.Extra = reader.GetInt32("extra"); + + auctionLot.MinStack = reader.GetInt32("min_stack"); // added in 5+ + auctionLot.MaxStack = reader.GetInt32("max_stack"); // added in 5+ + + AddAuctionLot(auctionLot); } } } + + ReadAuctionSoldsData(connection); } var auctionTask = new AuctionHouseTask(); TaskManager.Instance.Schedule(auctionTask, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5)); } + public (int, int) Save(MySqlConnection connection, MySqlTransaction transaction) { var deletedCount = 0; @@ -479,49 +509,86 @@ public void Load() } } - var dirtyItems = _auctionItems.Where(c => c.IsDirty == true); + var dirtyItems = AuctionLots.Where(c => c.IsDirty == true); foreach (var mtbs in dirtyItems) { + if (mtbs.Item == null) + continue; + + if (mtbs.Item.SlotType == SlotType.Invalid) + { + // Only give an error if it has no owner, otherwise it's likely a BuyBack item + if (mtbs.Item.OwnerId <= 0) + continue; + + // Try to re-attain the slot type by getting the owning container's type + if (mtbs.Item._holdingContainer != null) + { + mtbs.Item.SlotType = ItemManager.Instance.GetContainerSlotTypeByContainerId(mtbs.Item._holdingContainer.ContainerId); + } + + // If the slot type changed, give a warning, otherwise skip this save + if (mtbs.Item.SlotType != SlotType.Invalid) + { + Logger.Warn($"Slot type for {mtbs.Item.Id} was None, changing to {mtbs.Item.SlotType}"); + } + else + { + continue; + } + } + if (!Enum.IsDefined(typeof(SlotType), mtbs.Item.SlotType)) + { + Logger.Warn($"Found SlotType.{mtbs.Item.SlotType} in itemslist, skipping ID:{mtbs.Item.Id} - Template:{mtbs.Item.TemplateId}"); + continue; + } + + var details = new Commons.Network.PacketStream(); + mtbs.Item.WriteDetails(details); + using (var command = connection.CreateCommand()) { + // TODO отключим сохранение в базу + command.Connection = connection; command.Transaction = transaction; + command.CommandText = "REPLACE INTO auction_house(" + - "`id`, `duration`, `item_id`, `object_id`, `grade`, `flags`, `stack_size`, `detail_type`," + - " `creation_time`,`end_time`, `lifespan_mins`, `type_1`, `world_id`, `unsecure_date_time`, `unpack_date_time`," + - " `world_id_2`, `client_id`, `client_name`, `start_money`, `direct_money`, `bid_world_id`," + - " `bidder_id`, `bidder_name`, `bid_money`, `extra`" + + "`id`, `duration`," + + " `item_id`," + + "`end_time`," + + " `world_id`, `client_id`, `client_name`," + + " `start_money`, `direct_money`, `charge_percent`," + + " `bid_world_id`, `bidder_id`, `bidder_name`," + + " `bid_money`, `extra`, `min_stack`, `max_stack`" + ") VALUES (" + - "@id, @duration, @item_id, @object_id, @grade, @flags, @stack_size, @detail_type," + - " @creation_time, @end_time, @lifespan_mins, @type_1, @world_id, @unsecure_date_time, @unpack_date_time," + - " @world_id_2, @client_id, @client_name, @start_money, @direct_money, @bid_world_id," + - " @bidder_id, @bidder_name, @bid_money, @extra)"; + "@id, @duration," + + " @item_id," + + "@end_time," + + " @world_id, @client_id, @client_name," + + " @start_money, @direct_money, @charge_percent," + + " @bid_world_id, @bidder_id, @bidder_name," + + " @bid_money, @extra, @min_stack, @max_stack)"; + command.Parameters.AddWithValue("@id", mtbs.Id); - command.Parameters.AddWithValue("@duration", mtbs.Duration); - command.Parameters.AddWithValue("@item_id", mtbs.ItemId); - command.Parameters.AddWithValue("@object_id", mtbs.ObjectId); - command.Parameters.AddWithValue("@grade", mtbs.Grade); - command.Parameters.AddWithValue("@flags", mtbs.Flags); - command.Parameters.AddWithValue("@stack_size", mtbs.StackSize); - command.Parameters.AddWithValue("@detail_type", mtbs.DetailType); - command.Parameters.AddWithValue("@creation_time", mtbs.CreationTime); + command.Parameters.AddWithValue("@duration", (byte)mtbs.Duration); + + command.Parameters.AddWithValue("@item_id", mtbs.Item.Id); // item.Id + command.Parameters.AddWithValue("@end_time", mtbs.EndTime); - command.Parameters.AddWithValue("@lifespan_mins", mtbs.LifespanMins); - command.Parameters.AddWithValue("@type_1", mtbs.Type1); command.Parameters.AddWithValue("@world_id", mtbs.WorldId); - command.Parameters.AddWithValue("@unsecure_date_time", mtbs.UnsecureDateTime); - command.Parameters.AddWithValue("@unpack_date_time", mtbs.UnpackDateTime); - command.Parameters.AddWithValue("@world_id_2", mtbs.WorldId2); command.Parameters.AddWithValue("@client_id", mtbs.ClientId); command.Parameters.AddWithValue("@client_name", mtbs.ClientName); command.Parameters.AddWithValue("@start_money", mtbs.StartMoney); command.Parameters.AddWithValue("@direct_money", mtbs.DirectMoney); - command.Parameters.AddWithValue("@time_left", mtbs.TimeLeft); + command.Parameters.AddWithValue("@charge_percent", mtbs.ChargePercent); // added in 5+ command.Parameters.AddWithValue("@bid_world_id", mtbs.BidWorldId); command.Parameters.AddWithValue("@bidder_id", mtbs.BidderId); command.Parameters.AddWithValue("@bidder_name", mtbs.BidderName); command.Parameters.AddWithValue("@bid_money", mtbs.BidMoney); command.Parameters.AddWithValue("@extra", mtbs.Extra); + command.Parameters.AddWithValue("@min_stack", mtbs.MinStack); // added in 5+ + command.Parameters.AddWithValue("@max_stack", mtbs.MaxStack); // added in 5+ command.Prepare(); command.ExecuteNonQuery(); @@ -530,6 +597,495 @@ public void Load() } } + SaveSoldsData(connection); + return (updatedCount, deletedCount); } + + private List SortArticles(List articles, AuctionSearchSortKind kind, AuctionSearchSortOrder order) + { + if (kind == AuctionSearchSortKind.BidPrice) + { + if (order == AuctionSearchSortOrder.Asc) + { + return articles.OrderBy(o => o.BidMoney).ToList(); + } + + return articles.OrderByDescending(o => o.BidMoney).ToList(); + } + + if (kind == AuctionSearchSortKind.DirectPrice) + { + if (order == AuctionSearchSortOrder.Asc) + { + return articles.OrderBy(o => o.DirectMoney).ToList(); + } + + return articles.OrderByDescending(o => o.DirectMoney).ToList(); + } + + if (kind == AuctionSearchSortKind.ExpireDate) // TODO This will need to be fixed later due to varying durations + { + if (order == AuctionSearchSortOrder.Asc) + { + return articles.OrderBy(o => o.PostDate).ToList(); + } + + return articles.OrderByDescending(o => o.PostDate).ToList(); + } + + if (kind == AuctionSearchSortKind.ItemLevel) + { + if (order == AuctionSearchSortOrder.Asc) + { + return articles.OrderBy(o => o.Item.Template.Level).ToList(); + } + + return articles.OrderByDescending(o => o.Item.Template.Level).ToList(); + } + + return articles; + } + + public void SearchAuctionLots(Character player, AuctionSearch search) + { + var searchedArticles = new List(); + + var detectedLanguage = LanguageDetector.DetectLanguage(search.Keyword); + Logger.Info($"Detected language for keyword '{search.Keyword}': {detectedLanguage}"); + + foreach (var lot in AuctionLots) + { + var template = lot.Item.Template; + var settings = template.AuctionSettings; + + template.Name = GetLocalizedItemNameById(template.Id); + // Проверка по ClientId + if (search.ClientId != 0 && lot.ClientId != search.ClientId) + { + continue; + } + + // Проверка по ключевому слову + if (!string.IsNullOrEmpty(search.Keyword)) + { + var itemName = template.Name.ToLower(); + var keyword = search.Keyword.ToLower(); + + if (search.ExactMatch) + { + if (itemName != keyword) + { + continue; + } + } + else + { + if (!itemName.Contains(keyword)) + { + continue; + } + } + } + else + { + // Проверка по категориям и другим параметрам + if (settings.CategoryA != search.CategoryA && search.CategoryA != 0) + { + continue; + } + + if (settings.CategoryB != search.CategoryB && search.CategoryB != 0) + { + continue; + } + + if (settings.CategoryC != search.CategoryC && search.CategoryC != 0) + { + continue; + } + + if (lot.Item.Grade != search.Grade && search.Grade != 0) + { + continue; + } + + if (template.Level > search.MaxItemLevel && search.MaxItemLevel != 0) + { + continue; + } + + if (template.Level < search.MinItemLevel && search.MinItemLevel != 0) + { + continue; + } + } + + searchedArticles.Add(lot); + } + + if (searchedArticles.Count == 0) + { + player.SendPacket(new SCAuctionSearchedPacket(0, 0, [], (short)ErrorMessageType.NoErrorMessage, DateTime.UtcNow)); + return; + } + + var articles = SortArticles(searchedArticles, search.SortKind, search.SortOrder).ToArray(); + var dividedLists = Helpers.SplitArray(articles, 9); // Разделяем массив на массивы по 9 значений + player.SendPacket(new SCAuctionSearchedPacket(search.Page, dividedLists[search.Page].Length, dividedLists[search.Page].ToList(), (short)ErrorMessageType.NoErrorMessage, DateTime.UtcNow)); + } + + public void PostLotOnAuction(Character player, uint npcId, uint npcId2, ulong itemId, int startPrice, int buyoutPrice, AuctionDuration duration, int minStack, int maxStack) + { + var item = ItemManager.Instance.GetItemByItemId(itemId); + if (item == null) + { + return; + } + + var lot = CreateAuctionLot(player, item, startPrice, buyoutPrice, duration, minStack, maxStack); + if (lot == null) + { + return; + } + + var auctionFee = lot.DirectMoney * .01 * ((int)duration - 8 + 1); + + if (auctionFee > MaxListingFee) + { + auctionFee = MaxListingFee; + } + + if (!player.ChangeMoney(SlotType.Bag, -(int)auctionFee)) + { + player.SendErrorMessage(ErrorMessageType.CanNotPutupMoney); + return; + } + + player.Inventory.AuctionAttachments.AddOrMoveExistingItem(ItemTaskType.Auction, item); + + AddAuctionLot(lot); + player.SendPacket(new SCAuctionPostedPacket(lot)); + } + + private class LanguageDetector + { + private static readonly string[] CyrillicLanguages = ["ru", "uk", "bg", "sr", "mk"]; + private static readonly string[] LatinLanguages = ["en", "es", "fr", "de", "it"]; + + public static string DetectLanguage(string text) + { + if (string.IsNullOrEmpty(text)) + { + return "unknown"; + } + + // Проверка на кириллицу + if (text.Any(c => IsCyrillic(c))) + { + return "ru"; // Предполагаем русский язык, если есть кириллические символы + } + + // Проверка на латиницу + if (text.Any(c => IsLatin(c))) + { + return "en"; // Предполагаем английский язык, если есть латинские символы + } + + return "unknown"; + } + + private static bool IsCyrillic(char c) + { + return (c >= '\u0400' && c <= '\u04FF') || (c >= '\u0500' && c <= '\u052F'); + } + + private static bool IsLatin(char c) + { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } + } + + private void AddAuctionSold(AuctionLot lot) + { + var key = (lot.Item.TemplateId, lot.Item.Grade); + if (!SalesData.ContainsKey(key)) + { + SalesData[key] = new List<(DateTime, AuctionLot)>(); + } + SalesData[key].Add((DateTime.UtcNow, lot)); + } + + public List GetSalesForLast14Days(uint itemTemplateId, byte itemGradeId) + { + var key = (itemTemplateId, itemGradeId); + var result = new List(); + + // Создаем список из 14 дней с нулевыми значениями + for (var i = 0; i < 14; i++) + { + result.Add(new AuctionSold + { + ItemId = itemTemplateId, + Day = i + 1, + MinCopper = 0, + MaxCopper = 0, + AvgCopper = 0, + Volume = 0, + ItemGrade = itemGradeId, + WeeklyAvgCopper = 0 + }); + } + + if (SalesData.Count != 0) + { + var sales = SalesData[key]; + var salesByDay = sales.GroupBy(s => s.Date.Date).OrderBy(g => g.Key).TakeLast(14); + + foreach (var daySales in salesByDay) + { + var day = (daySales.Key - DateTime.UtcNow.Date).Days + 1; + var salesForDay = daySales.ToList(); + + if (salesForDay.Count > 0) + { + var minCopper = salesForDay.Min(s => s.Lot.BidMoney); + var maxCopper = salesForDay.Max(s => s.Lot.BidMoney); + var avgCopper = (long)salesForDay.Average(s => s.Lot.BidMoney); + var volume = salesForDay.Sum(s => s.Lot.Extra); + + // Расчет WeeklyAvgCopper + var weeklySales = salesByDay.Where(g => (g.Key - daySales.Key).Days >= 0 && (g.Key - daySales.Key).Days < 7).SelectMany(g => g); + var weeklyAvgCopper = weeklySales.Any() ? (long)weeklySales.Average(s => s.Lot.BidMoney) : 0; + + result[14 - day] = new AuctionSold + { + ItemId = itemTemplateId, + Day = day, + MinCopper = minCopper, + MaxCopper = maxCopper, + AvgCopper = avgCopper, + Volume = volume, + ItemGrade = itemGradeId, + WeeklyAvgCopper = weeklyAvgCopper + }; + } + } + + // Сохраняем результат в SoldsData + if (!SoldsData.ContainsKey(key)) + { + SoldsData[key] = []; + } + + for (var i = 0; i < 14; i++) + { + var date = DateTime.UtcNow.Date.AddDays(-i); + var sold = result[14 - i - 1]; + SoldsData[key].Add((date, sold)); + } + } + else + { + var res = GetLast14AuctionSoldByItemId(MySQL.CreateConnection(), key); + if (res.Count > 0) + { + result = res; + } + } + + return result; + } + + private List GetLast14AuctionSoldByItemId(MySqlConnection connection, (uint itemTemplateId, byte itemGradeId) key) + { + + //public static List<(DateTime Date, AuctionSold Sold)> GetLast14AuctionSoldByItemId(MySqlConnection connection, (uint itemTemplateId, byte itemGradeId) key) + + // Список для хранения данных + var last14AuctionSold = new List(); + + // SQL-запрос для выборки данных с использованием ROW_NUMBER() + var query = @" + WITH RankedData AS ( + SELECT + item_id, + item_grade, + date, + min_copper, + max_copper, + avg_copper, + volume, + weekly_avg_copper, + ROW_NUMBER() OVER (PARTITION BY item_id, item_grade ORDER BY date ASC) AS rn + FROM + auction_solds_data + WHERE + item_id = @itemTemplateId AND item_grade = @itemGradeId + ) + SELECT + item_id, + item_grade, + date, + min_copper, + max_copper, + avg_copper, + volume, + weekly_avg_copper, + rn + FROM + RankedData + WHERE + rn <= 14"; + + var command = new MySqlCommand(query, connection); + command.Parameters.AddWithValue("@itemTemplateId", key.itemTemplateId); + command.Parameters.AddWithValue("@itemGradeId", key.itemGradeId); + + using var reader = command.ExecuteReader(); + while (reader.Read()) + { + var itemId = reader.GetUInt32("item_id"); + var itemGrade = reader.GetByte("item_grade"); + var date = reader.GetDateTime("date"); + var minCopper = reader.GetInt64("min_copper"); + var maxCopper = reader.GetInt64("max_copper"); + var avgCopper = reader.GetInt64("avg_copper"); + var volume = reader.GetInt32("volume"); + var weeklyAvgCopper = reader.GetInt64("weekly_avg_copper"); + var day = reader.GetInt32("rn"); // Номер строки (ранг) + + // Создаем объект AuctionSold + var sold = new AuctionSold + { + ItemId = itemId, + ItemGrade = itemGrade, + MinCopper = minCopper, + MaxCopper = maxCopper, + AvgCopper = avgCopper, + Volume = volume, + WeeklyAvgCopper = weeklyAvgCopper, + Day = day + }; + + // Добавляем данные в список + last14AuctionSold.Add(sold); + } + + return last14AuctionSold; + } + + private void ReadAuctionSoldsData(MySqlConnection connection) + { + // SQL-запрос для выборки данных с использованием ROW_NUMBER() + var query = @" + WITH RankedData AS ( + SELECT + item_id, + item_grade, + date, + min_copper, + max_copper, + avg_copper, + volume, + weekly_avg_copper, + ROW_NUMBER() OVER (PARTITION BY item_id, item_grade ORDER BY date ASC) AS rn + FROM + auction_solds_data + ) + SELECT + item_id, + item_grade, + date, + min_copper, + max_copper, + avg_copper, + volume, + weekly_avg_copper, + rn + FROM + RankedData + WHERE + rn <= 14"; + + var command = new MySqlCommand(query, connection); + using var reader = command.ExecuteReader(); + while (reader.Read()) + { + var itemId = reader.GetUInt32("item_id"); + var itemGrade = reader.GetByte("item_grade"); + var date = reader.GetDateTime("date"); + var minCopper = reader.GetInt64("min_copper"); + var maxCopper = reader.GetInt64("max_copper"); + var avgCopper = reader.GetInt64("avg_copper"); + var volume = reader.GetInt32("volume"); + var weeklyAvgCopper = reader.GetInt64("weekly_avg_copper"); + var day = reader.GetInt32("rn"); // Номер строки (ранг) + + // Создаем объект AuctionSold + var sold = new AuctionSold + { + ItemId = itemId, + ItemGrade = itemGrade, + MinCopper = minCopper, + MaxCopper = maxCopper, + AvgCopper = avgCopper, + Volume = volume, + WeeklyAvgCopper = weeklyAvgCopper, + Day = day + }; + + // Добавляем данные в словарь + var key = (itemId, itemGrade); + if (!SoldsData.ContainsKey(key)) + { + SoldsData[key] = new List<(DateTime, AuctionSold)>(); + } + SoldsData[key].Add((date, sold)); + } + } + + private void SaveSoldsData(MySqlConnection connection) + { + if (connection.State != System.Data.ConnectionState.Open) + { + connection.Open(); + } + + try + { + foreach (var (key, solds) in SoldsData) + { + foreach (var (date, sold) in solds) + { + SaveAuctionSold(connection, sold, date); + } + } + + } + catch (Exception ex) + { + throw new Exception("Failed to save solds data to the database.", ex); + } + } + + private static void SaveAuctionSold(MySqlConnection connection, AuctionSold auctionSold, DateTime date) + { + using var command = connection.CreateCommand(); + command.CommandText = "INSERT INTO auction_solds_data (item_id, item_grade, date, min_copper, max_copper, avg_copper, volume, weekly_avg_copper) " + + "VALUES (@item_id, @item_grade, @date, @min_copper, @max_copper, @avg_copper, @volume, @weekly_avg_copper) " + + "ON DUPLICATE KEY UPDATE min_copper = @min_copper, max_copper = @max_copper, avg_copper = @avg_copper, volume = @volume, weekly_avg_copper = @weekly_avg_copper;"; + + command.Parameters.AddWithValue("@item_id", auctionSold.ItemId); + command.Parameters.AddWithValue("@item_grade", auctionSold.ItemGrade); + command.Parameters.AddWithValue("@date", date); + command.Parameters.AddWithValue("@min_copper", auctionSold.MinCopper); + command.Parameters.AddWithValue("@max_copper", auctionSold.MaxCopper); + command.Parameters.AddWithValue("@avg_copper", auctionSold.AvgCopper); + command.Parameters.AddWithValue("@volume", auctionSold.Volume); + command.Parameters.AddWithValue("@weekly_avg_copper", auctionSold.WeeklyAvgCopper); + + command.Prepare(); + command.ExecuteNonQuery(); + } } diff --git a/AAEmu.Game/Core/Managers/GameScheduleManager.cs b/AAEmu.Game/Core/Managers/GameScheduleManager.cs index c27b4e2e7f..3882b01f1c 100644 --- a/AAEmu.Game/Core/Managers/GameScheduleManager.cs +++ b/AAEmu.Game/Core/Managers/GameScheduleManager.cs @@ -5,9 +5,13 @@ using AAEmu.Commons.Utils; using AAEmu.Game.GameData; using AAEmu.Game.Models.Game.Schedules; + using NCrontab; + using NLog; + using static System.String; + using DayOfWeek = AAEmu.Game.Models.Game.Schedules.DayOfWeek; namespace AAEmu.Game.Core.Managers; @@ -22,6 +26,7 @@ public class GameScheduleManager : Singleton private Dictionary _gameScheduleDoodads; private Dictionary> _gameScheduleDoodadIds; private Dictionary _gameScheduleQuests; + private Dictionary _scheduleItems; private List GameScheduleId { get; set; } public void Load() @@ -65,6 +70,11 @@ public void LoadGameScheduleQuests(Dictionary gameSched _gameScheduleQuests = gameScheduleQuests; } + public void LoadScheduleItems(Dictionary scheduleItems) + { + _scheduleItems = scheduleItems; + } + public bool CheckSpawnerInScheduleSpawners(int spawnerId) { return _gameScheduleSpawnerIds.ContainsKey(spawnerId); @@ -188,6 +198,12 @@ private List CheckScheduler() return res; } + public ScheduleItems GetScheduleItem(uint id) + { + _scheduleItems.TryGetValue(id, out var value); + return value; + } + public string GetCronRemainingTime(int spawnerId, bool start = true) { var cronExpression = Empty; @@ -529,4 +545,57 @@ 7. Year (optional field) / Год (необязательное поле) // Not return cronExpression; } + + public List GetMatchingPeriods2() + { + var matchingPeriods = new List(); + var now = DateTime.Now; + + foreach (var period in _scheduleItems.Values) + { + var startDate = new DateTime((int)period.StYear, (int)period.StMonth, (int)period.StDay, (int)period.StHour, (int)period.StMin, 0); + var endDate = new DateTime((int)period.EdYear, (int)period.EdMonth, (int)period.EdDay, (int)period.EdHour, (int)period.EdMin, 59); + + if (now >= startDate && now <= endDate) + { + matchingPeriods.Add(period.Id); + } + } + + return matchingPeriods; + } + + public List GetMatchingPeriods() + { + var matchingPeriods = new List(); + var now = DateTime.UtcNow; + + foreach (var period in _scheduleItems.Values) + { + var startDate = new DateTime( + period.StYear == 0 ? now.Year : (int)period.StYear, + period.StMonth == 0 ? now.Month : (int)period.StMonth, + period.StDay == 0 ? now.Day : (int)period.StDay, + (int)period.StHour, + (int)period.StMin, + 0 + ); + + var endDate = new DateTime( + period.EdYear == 0 ? now.Year : (int)period.EdYear, + period.EdMonth == 0 ? now.Month : (int)period.EdMonth, + period.EdDay == 0 ? now.Day : (int)period.EdDay, + (int)period.EdHour, + (int)period.EdMin, + 59 + ); + + if (now >= startDate && now <= endDate && period.ActiveTake) + { + matchingPeriods.Add(period.Id); + } + } + + return matchingPeriods; + } } diff --git a/AAEmu.Game/Core/Managers/HousingManager.cs b/AAEmu.Game/Core/Managers/HousingManager.cs index 67aba8f241..45fa322ba4 100644 --- a/AAEmu.Game/Core/Managers/HousingManager.cs +++ b/AAEmu.Game/Core/Managers/HousingManager.cs @@ -22,6 +22,7 @@ using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; using AAEmu.Game.Models.Game.Skills; using AAEmu.Game.Models.Game.World.Transform; using AAEmu.Game.Models.StaticValues; @@ -589,8 +590,8 @@ public void Build(GameConnection connection, uint designId, float posX, float po { // Pay in Tax Certificate - var userTaxCount = connection.ActiveChar.Inventory.GetItemsCount(SlotType.Inventory, Item.TaxCertificate); - var userBoundTaxCount = connection.ActiveChar.Inventory.GetItemsCount(SlotType.Inventory, Item.BoundTaxCertificate); + var userTaxCount = connection.ActiveChar.Inventory.GetItemsCount(SlotType.Bag, Item.TaxCertificate); + var userBoundTaxCount = connection.ActiveChar.Inventory.GetItemsCount(SlotType.Bag, Item.BoundTaxCertificate); var totalUserTaxCount = userTaxCount + userBoundTaxCount; var totalCertsCost = (int)Math.Ceiling(totalTaxAmountDue / 10000f); @@ -634,7 +635,7 @@ public void Build(GameConnection connection, uint designId, float posX, float po connection.ActiveChar.SendErrorMessage(ErrorMessageType.MailNotEnoughMoneyToPayTaxes); return; } - connection.ActiveChar.SubtractMoney(SlotType.Inventory, totalTaxAmountDue, ItemTaskType.HouseCreation); + connection.ActiveChar.SubtractMoney(SlotType.Bag, totalTaxAmountDue, ItemTaskType.HouseCreation); } if (connection.ActiveChar.Inventory.Bag.ConsumeItem(ItemTaskType.HouseBuilding, sourceDesignItem.TemplateId, 1, sourceDesignItem) <= 0) @@ -673,7 +674,7 @@ public void Build(GameConnection connection, uint designId, float posX, float po house.ProtectionEndDate = DateTime.UtcNow.AddDays(TaxPaysForDays); _houses.Add(house.Id, house); _housesTl.Add(house.TlId, house); - connection.ActiveChar.SendPacket(new SCMyHousePacket(house)); + connection.ActiveChar.SendPacket(new SCHouseStatePacket(house)); house.Spawn(); UpdateTaxInfo(house); ResidentManager.Instance.AddResidenMemberInfo(connection.ActiveChar); @@ -711,7 +712,7 @@ public void ChangeHouseName(GameConnection connection, ushort tlId, string name) if (house.OwnerId != connection.ActiveChar.Id) return; - house.Name = string.Concat(name.Substring(0, 1).ToUpper(), name.AsSpan(1)); + house.Name = name.NormalizeName(); house.IsDirty = true; // Manually set the IsDirty on House level connection.SendPacket(new SCUnitNameChangedPacket(house.ObjId, house.Name)); } @@ -988,7 +989,7 @@ private void ReturnHouseItemsToOwner(House house, bool failedToPayTax, bool forc { designItem.Grade = (designTemplate.FixedGrade >= 0) ? (byte)designTemplate.FixedGrade : (byte)0; designItem.OwnerId = house.OwnerId; - designItem.SlotType = SlotType.Mail; + designItem.SlotType = SlotType.MailAttachment; returnedItems.Add(designItem); } @@ -999,7 +1000,7 @@ private void ReturnHouseItemsToOwner(House house, bool failedToPayTax, bool forc { var taxItem = ItemManager.Instance.Create(Item.BoundTaxCertificate, (int)(house.Template.Taxation.Tax / 5000), 0); taxItem.OwnerId = house.OwnerId; - taxItem.SlotType = SlotType.Mail; + taxItem.SlotType = SlotType.MailAttachment; returnedItems.Add(taxItem); } else @@ -1062,7 +1063,7 @@ private void ReturnHouseItemsToOwner(House house, bool failedToPayTax, bool forc { // TODO: Check if items should stay in the coffer when house is sold. // Move it to new owner's SystemContainer first so they don't get destroyed - var ownerSystemContainer = ItemManager.Instance.GetItemContainerForCharacter(house.OwnerId, SlotType.System, null, 0); + var ownerSystemContainer = ItemManager.Instance.GetItemContainerForCharacter(house.OwnerId, SlotType.Money, null, 0); for (var i = coffer.ItemContainer.Items.Count - 1; i >= 0; i--) { var cofferItem = coffer.ItemContainer.Items[i]; @@ -1111,7 +1112,7 @@ private void ReturnHouseItemsToOwner(House house, bool failedToPayTax, bool forc if (f.ItemId > 0) { // Ignore if it's not in a System container for whatever reason - if (thisDoodadsItem is { SlotType: SlotType.System }) + if (thisDoodadsItem is { SlotType: SlotType.Money }) { returnedItems.Add(thisDoodadsItem); returnedThisItem = true; @@ -1135,7 +1136,7 @@ private void ReturnHouseItemsToOwner(House house, bool failedToPayTax, bool forc var furnitureTemplate = ItemManager.Instance.GetTemplate(f.ItemTemplateId); furnitureItem.Grade = (furnitureTemplate.FixedGrade >= 0) ? (byte)furnitureTemplate.FixedGrade : (byte)0; furnitureItem.OwnerId = house.OwnerId; - furnitureItem.SlotType = SlotType.Mail; + furnitureItem.SlotType = SlotType.MailAttachment; returnedItems.Add(furnitureItem); } returnedThisItem = true; @@ -1196,7 +1197,7 @@ private void ReturnHouseItemsToOwner(House house, bool failedToPayTax, bool forc if (onlineOwner != null) onlineOwner.Inventory.MailAttachments.AddOrMoveExistingItem(ItemTaskType.Invalid, returnedItems[i]); else - returnedItems[i].SlotType = SlotType.Mail; + returnedItems[i].SlotType = SlotType.MailAttachment; // Attach item newMail.Body.Attachments.Add(returnedItems[i]); @@ -1477,7 +1478,7 @@ public bool BuyHouse(ushort houseTlId, uint money, Character character) // NOTE: check tax due maybe ? - if (!character.SubtractMoney(SlotType.Inventory, (int)house.SellPrice, ItemTaskType.BuyHouse)) + if (!character.SubtractMoney(SlotType.Bag, (int)house.SellPrice, ItemTaskType.BuyHouse)) { // Not enough money character.SendErrorMessage(ErrorMessageType.HouseCannotBuyAsNotEnoughMoney); @@ -1547,7 +1548,7 @@ public bool BuyHouse(ushort houseTlId, uint money, Character character) SetForSaleMarkers(house, false); - character.SendPacket(new SCMyHousePacket(house)); + character.SendPacket(new SCHouseStatePacket(house)); var oldOwner = WorldManager.Instance.GetCharacterById(previousOwner); if ((oldOwner != null) && (oldOwner.IsOnline)) oldOwner.SendPacket(new SCHouseRemovedPacket(house.TlId)); diff --git a/AAEmu.Game/Core/Managers/ItemManager.cs b/AAEmu.Game/Core/Managers/ItemManager.cs index c5713908db..2ead2069ba 100644 --- a/AAEmu.Game/Core/Managers/ItemManager.cs +++ b/AAEmu.Game/Core/Managers/ItemManager.cs @@ -10,7 +10,7 @@ using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.GameData; -using AAEmu.Game.Models.Game.Auction.Templates; +using AAEmu.Game.Models.Game.Auction; using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Formulas; using AAEmu.Game.Models.Game.Items; @@ -361,7 +361,7 @@ public bool TookLootDropItem(Character character, List lootDropItems, Item var objId = (uint)(lootDropItem.Id >> 32); if (lootDropItem.TemplateId == Item.Coins) { - character.AddMoney(SlotType.Inventory, lootDropItem.Count); + character.AddMoney(SlotType.Bag, lootDropItem.Count); } else { @@ -474,13 +474,13 @@ private List GetItemIdsBySearchName(string searchString) return res; } - public List GetItemTemplatesForAuctionSearch(AuctionSearchTemplate searchTemplate) + public List GetItemTemplatesForAuctionSearch(AuctionSearch searchTemplate) { var templateList = new List(); var itemIds = new List(); - if (searchTemplate.ItemName != "") - itemIds = GetItemIdsBySearchName(searchTemplate.ItemName); + if (searchTemplate.Keyword != "") + itemIds = GetItemIdsBySearchName(searchTemplate.Keyword); if (itemIds.Count > 0) { @@ -1225,6 +1225,14 @@ public void Load() template.LivingPointPrice = reader.GetInt32("living_point_price"); template.CharGender = reader.GetByte("char_gender_id"); + template.AuctionSettings = new AuctionSettings( + template.AuctionCategoryA, + template.AuctionCategoryB, + template.AuctionCategoryC, + reader.GetUInt32("auction_charge"), + reader.GetBoolean("auction_charge_default") + ); + _templates.TryAdd(template.Id, template); } } @@ -1703,7 +1711,7 @@ public uint GetSlaveIdByItemId(uint itemId) { foreach (var (_, c) in _allPersistentContainers) { - if (c.ContainerType == SlotType.None) + if (c.ContainerType == SlotType.Invalid) continue; // Skip the BuyBack container if (c.ContainerId <= 0) @@ -1721,7 +1729,7 @@ public uint GetSlaveIdByItemId(uint itemId) command.Parameters.Clear(); command.Parameters.AddWithValue("@container_id", c.ContainerId); command.Parameters.AddWithValue("@container_type", c.ContainerTypeName()); - command.Parameters.AddWithValue("@slot_type", c.ContainerType.ToString()); + command.Parameters.AddWithValue("@slot_type", (int)c.ContainerType); command.Parameters.AddWithValue("@container_size", c.ContainerSize); command.Parameters.AddWithValue("@owner_id", c.OwnerId); command.Parameters.AddWithValue("@mate_id", c.MateId); @@ -1753,7 +1761,7 @@ public uint GetSlaveIdByItemId(uint itemId) if (item == null) continue; - if (item.SlotType == SlotType.None) + if (item.SlotType == SlotType.Invalid) { // Only give an error if it has no owner, otherwise it's likely a BuyBack item if (item.OwnerId <= 0) @@ -1766,7 +1774,7 @@ public uint GetSlaveIdByItemId(uint itemId) } // If the slot type changed, give a warning, otherwise skip this save - if (item.SlotType != SlotType.None) + if (item.SlotType != SlotType.Invalid) { Logger.Warn($"Slot type for {item.Id} was None, changing to {item.SlotType}"); } @@ -1801,7 +1809,7 @@ public uint GetSlaveIdByItemId(uint itemId) command.Parameters.AddWithValue("@type", item.GetType().ToString()); command.Parameters.AddWithValue("@template_id", item.TemplateId); command.Parameters.AddWithValue("@container_id", item._holdingContainer?.ContainerId ?? 0); - command.Parameters.AddWithValue("@slot_type", item.SlotType.ToString()); + command.Parameters.AddWithValue("@slot_type", (int)item.SlotType); command.Parameters.AddWithValue("@slot", item.Slot); command.Parameters.AddWithValue("@count", item.Count); command.Parameters.AddWithValue("@details", details.GetBytes()); @@ -1846,7 +1854,7 @@ public uint GetSlaveIdByItemId(uint itemId) return (updateCount, deleteCount, containerUpdateCount); } - private SlotType GetContainerSlotTypeByContainerId(ulong dbId) + public SlotType GetContainerSlotTypeByContainerId(ulong dbId) { _allPersistentContainers.TryGetValue(dbId, out var container); @@ -1855,7 +1863,7 @@ private SlotType GetContainerSlotTypeByContainerId(ulong dbId) return container.ContainerType; } - return SlotType.None; + return SlotType.Invalid; } /// @@ -1881,14 +1889,15 @@ public ItemContainer GetItemContainerForCharacter(uint characterId, SlotType slo var newContainerType = slotType switch { SlotType.Equipment => "EquipmentContainer", - SlotType.EquipmentMate => "MateEquipmentContainer", - SlotType.EquipmentSlave => "SlaveEquipmentContainer", + SlotType.PetRideEquipment => "MateEquipmentContainer", + SlotType.SlaveEquipment => "SlaveEquipmentContainer", + SlotType.Auction => "AuctionContainer", _ => "ItemContainer" }; - var newContainer = ItemContainer.CreateByTypeName(newContainerType, characterId, slotType, slotType != SlotType.None, parentUnit); + var newContainer = ItemContainer.CreateByTypeName(newContainerType, characterId, slotType, slotType != SlotType.Invalid, parentUnit); - if (slotType != SlotType.None) + if (slotType != SlotType.Invalid) _allPersistentContainers.Add(newContainer.ContainerId, newContainer); if (mateId > 0) @@ -1976,7 +1985,7 @@ public void LoadUserItems() { var containerId = reader.GetUInt32("container_id"); var containerType = reader.GetString("container_type"); - var slotType = (SlotType)Enum.Parse(typeof(SlotType), reader.GetString("slot_type"), true); + var slotType = (SlotType)reader.GetInt32("slot_type"); var containerSize = reader.GetInt32("container_size"); var containerOwnerId = reader.GetUInt32("owner_id"); var containerMateId = reader.GetUInt32("mate_id"); @@ -2045,11 +2054,7 @@ public void LoadUserItems() item.TemplateId = itemTemplateId; item.Template = GetTemplate(item.TemplateId); var containerId = reader.GetUInt64("container_id"); - var slotTypeString = reader.GetString("slot_type"); - if (Enum.IsDefined(typeof(SlotType), slotTypeString)) - item.SlotType = (SlotType)Enum.Parse(typeof(SlotType), slotTypeString, true); - else - item.SlotType = SlotType.System; + item.SlotType = (SlotType)reader.GetInt32("slot_type"); var thisItemSlot = reader.GetInt32("slot"); item.Slot = thisItemSlot; item.Count = reader.GetInt32("count"); diff --git a/AAEmu.Game/Core/Managers/MailManager.cs b/AAEmu.Game/Core/Managers/MailManager.cs index 8d6347bd69..103d9b120f 100644 --- a/AAEmu.Game/Core/Managers/MailManager.cs +++ b/AAEmu.Game/Core/Managers/MailManager.cs @@ -8,12 +8,12 @@ using AAEmu.Game.Core.Managers.Id; using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Packets.G2C; -using AAEmu.Game.Models.Game; using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Features; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; using AAEmu.Game.Models.Game.Quests; using AAEmu.Game.Models.Tasks.Mails; @@ -86,8 +86,7 @@ public bool Send(BaseMail mail) } [Obsolete("SendMail() is deprecated. Use Send() of a BaseMail descendant instead.")] - public void SendMail(MailType type, string receiverName, string senderName, string title, string text, - byte attachments, int[] moneyAmounts, long extra, List items) + public void SendMail(MailType type, string receiverName, string senderName, string title, string text, byte attachments, int[] moneyAmounts, long extra, List items) { throw new GameException("SendMail is deprecated, use BaseMail.Send() instead"); } @@ -286,13 +285,13 @@ public Dictionary GetCurrentMailList(Character character) character.Mails.UnreadMailCount.ResetReceived(); foreach (var mail in tempMails) { - //if ((mail.Value.Header.Status != MailStatus.Read) && (mail.Value.Header.SenderId != character.Id)) + character.Mails.UnreadMailCount.UpdateReceived(mail.Value.MailType, 1); if (mail.Value.Header.Status != MailStatus.Read) { - character.Mails.UnreadMailCount.UpdateReceived(mail.Value.MailType, 1); + character.Mails.UnreadMailCount.UpdateUnreadReceived(mail.Value.MailType, 1); var addBody = (mail.Value.MailType == MailType.Charged); - character.SendPacket(new SCGotMailPacket(mail.Value.Header, character.Mails.UnreadMailCount, false, addBody ? mail.Value.Body : null)); + //character.SendPacket(new SCGotMailPacket(mail.Value.Header, character.Mails.UnreadMailCount, false, addBody ? mail.Value.Body : null)); mail.Value.IsDelivered = true; } } @@ -311,6 +310,7 @@ public static bool NotifyNewMailByNameIfOnline(BaseMail m, string receiverName) // TODO: Mia mail stuff var addBody = (m.MailType == MailType.Charged); player.Mails.UnreadMailCount.UpdateReceived(m.MailType, 1); + player.Mails.UnreadMailCount.UpdateUnreadReceived(m.MailType, 1); player.SendPacket(new SCGotMailPacket(m.Header, player.Mails.UnreadMailCount, false, addBody ? m.Body : null)); m.IsDelivered = true; @@ -326,8 +326,9 @@ public static bool NotifyDeleteMailByNameIfOnline(BaseMail m, string receiverNam var player = WorldManager.Instance.GetCharacter(receiverName); if (player != null) { + player.Mails.UnreadMailCount.UpdateReceived(m.MailType, -1); if (m.Header.Status != MailStatus.Read) - player.Mails.UnreadMailCount.UpdateReceived(m.MailType, -1); + player.Mails.UnreadMailCount.UpdateUnreadReceived(m.MailType, -1); player.SendPacket(new SCMailDeletedPacket(false, m.Id, true, player.Mails.UnreadMailCount)); return true; } @@ -379,8 +380,8 @@ public bool PayChargeMoney(Character character, long mailId, bool autoUseAAPoint { // use Tax Certificates as payment // TODO: grab these values from DB somewhere ? - var userTaxCount = character.Inventory.GetItemsCount(SlotType.Inventory, Item.TaxCertificate); - var userBoundTaxCount = character.Inventory.GetItemsCount(SlotType.Inventory, Item.BoundTaxCertificate); + var userTaxCount = character.Inventory.GetItemsCount(SlotType.Bag, Item.TaxCertificate); + var userBoundTaxCount = character.Inventory.GetItemsCount(SlotType.Bag, Item.BoundTaxCertificate); var totatUserTaxCount = userTaxCount + userBoundTaxCount; var consumedCerts = (int)Math.Ceiling(mail.Body.BillingAmount / 10000f); @@ -428,7 +429,7 @@ public bool PayChargeMoney(Character character, long mailId, bool autoUseAAPoint } else { - character.SubtractMoney(SlotType.Inventory, mail.Body.BillingAmount); + character.SubtractMoney(SlotType.Bag, mail.Body.BillingAmount); } } @@ -532,7 +533,7 @@ public static List CreateQuestRewardMails(ICharacter character, Quest if ((mail == null) || (mail.Body.Attachments.Count >= 10)) { mail = new MailPlayerToPlayer(character, character.Name); - mail.Header.SenderId = 0; + mail.Header.SenderId = (uint)SystemMailSenderKind.None; mail.Header.SenderName = ".questReward"; mail.MailType = MailType.SysExpress; // NOTE: On newer versions, this uses the .title / .body format, but this doesn't seem to work on 1.2 diff --git a/AAEmu.Game/Core/Managers/ManaRegenManager.cs b/AAEmu.Game/Core/Managers/ManaRegenManager.cs new file mode 100644 index 0000000000..8439822751 --- /dev/null +++ b/AAEmu.Game/Core/Managers/ManaRegenManager.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; + +using AAEmu.Commons.Utils; +using AAEmu.Game.Models.Game.Char; +using AAEmu.Game.Models.Game.Skills; +using AAEmu.Game.Models.Game.Skills.Buffs; + +namespace AAEmu.Game.Core.Managers; + +public class ManaRegenManager : Singleton +{ + private int UpdateDelay { get; set; } = 200; // Интервал тика баффа в миллисекундах + private static object Lock { get; } = new(); + private Dictionary Registrations { get; set; } + + public void Initialize() + { + Registrations = new Dictionary(); + TickManager.Instance.OnTick.Subscribe(Tick, TimeSpan.FromMilliseconds(UpdateDelay), true); + } + + internal void Register(Character player, ManaRegenTemplate template) + { + lock (Lock) + { + // If no entry, create one + if (!Registrations.TryGetValue(player.Id, out var entry)) + { + Registrations.Add(player.Id, template); + } + + // If nothing set, delete + //Registrations.Remove(player.Id); + } + } + + private void Tick(TimeSpan delta) + { + lock (Lock) + { + if (Registrations.Count <= 0) + return; + + foreach (var (_, entry) in Registrations) + { + if (!entry.ApplyBuff(entry.Owner)) + { + UnRegister(entry.Owner); + entry.Owner.Buffs.RemoveBuff((uint)BuffConstants.Dash); + } + + } // for each player + } // lock + } + + private void UnRegister(Character player) + { + lock (Lock) + { + Registrations.Remove(player.Id); + } + } +} diff --git a/AAEmu.Game/Core/Managers/MateManager.cs b/AAEmu.Game/Core/Managers/MateManager.cs index 4064f19655..246c7c8a06 100644 --- a/AAEmu.Game/Core/Managers/MateManager.cs +++ b/AAEmu.Game/Core/Managers/MateManager.cs @@ -17,6 +17,8 @@ using AAEmu.Game.Models.Game.Units; using AAEmu.Game.Utils.DB; +using Discord; + using NLog; namespace AAEmu.Game.Core.Managers; @@ -132,10 +134,21 @@ public void ChangeTargetMate(GameConnection connection, uint tlId, uint objId) public Mate RenameMount(GameConnection connection, uint tlId, string newName) { var (owner, mateInfo) = GetMateInfoByTlId(connection, tlId); - if (string.IsNullOrWhiteSpace(newName) || newName.Length == 0 || !_nameRegex.IsMatch(newName)) return null; - if (mateInfo?.TlId != tlId) return null; + if (string.IsNullOrWhiteSpace(newName) || newName.Length == 0 || !_nameRegex.IsMatch(newName)) + { + Logger.Warn($"{owner.Name} The pet's name must not be the same as the character's name!"); + return null; + } + + if (mateInfo?.TlId != tlId) + { + Logger.Warn($"{owner.Name} no pet active!"); + return null; + } + mateInfo.Name = newName.NormalizeName(); owner.BroadcastPacket(new SCUnitNameChangedPacket(mateInfo.ObjId, newName), true); + return mateInfo; } @@ -420,6 +433,10 @@ public void RemoveActiveMateAndDespawn(Character owner, Mate mateInfo) ObjectIdManager.Instance.ReleaseId(mateInfo.ObjId); TlIdManager.Instance.ReleaseId(mateInfo.TlId); + var item = owner.Inventory.GetItemById(mateInfo.ItemId); + if (item is not null) + owner.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.MateDeath, [new ItemUpdate(item)], [])); + Logger.Debug($"Mount removed: OwnerObjId={owner.ObjId}, tlId={mateInfo.TlId}, mateObjId={mateInfo.ObjId}"); } diff --git a/AAEmu.Game/Core/Managers/PortalManager.cs b/AAEmu.Game/Core/Managers/PortalManager.cs index 82f474045f..0224f691e0 100644 --- a/AAEmu.Game/Core/Managers/PortalManager.cs +++ b/AAEmu.Game/Core/Managers/PortalManager.cs @@ -15,7 +15,6 @@ using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; -using AAEmu.Game.Models.Game.NPChar; using AAEmu.Game.Models.Game.OpenPortal; using AAEmu.Game.Models.Game.Skills; using AAEmu.Game.Models.Game.Teleport; @@ -341,8 +340,8 @@ public void Load() public static bool CheckItemAndRemove(Character owner, uint itemId, int amount) { - if (!owner.Inventory.CheckItems(SlotType.Inventory, itemId, amount)) return false; - owner.Inventory.Bag.ConsumeItem(ItemTaskType.Teleport, itemId, amount, null); + if (!owner.Inventory.CheckItems(SlotType.Bag, itemId, amount)) return false; + owner.Inventory.Bag.ConsumeItem(ItemTaskType.RecoverDoodadItem, itemId, amount, null); return true; /* var items = owner.Inventory.RemoveItem(itemId, amount); diff --git a/AAEmu.Game/Core/Managers/ShipyardManager.cs b/AAEmu.Game/Core/Managers/ShipyardManager.cs index 1f38bbe275..5fbeefaf73 100644 --- a/AAEmu.Game/Core/Managers/ShipyardManager.cs +++ b/AAEmu.Game/Core/Managers/ShipyardManager.cs @@ -107,7 +107,7 @@ private static bool RemoveRequiredItems(Shipyard shipyard) var designId = shipyard.Template.OriginItemId; var moneyOwed = TaxationsManager.Instance.taxations[(uint)shipyard.Template.TaxationId].Tax; - if (!character.Inventory.CheckItems(SlotType.Inventory, designId, 1)) + if (!character.Inventory.CheckItems(SlotType.Bag, designId, 1)) { character.SendErrorMessage(ErrorMessageType.NotEnoughItem); Logger.Error("Not enough item Id={0}", designId); @@ -135,7 +135,7 @@ private static bool RemoveRequiredItems(Shipyard shipyard) var enough = true; foreach (var reagent in reagents) { - if (character.Inventory.CheckItems(SlotType.Inventory, reagent.ItemId, reagent.Amount)) + if (character.Inventory.CheckItems(SlotType.Bag, reagent.ItemId, reagent.Amount)) { continue; } @@ -168,7 +168,7 @@ private static bool RemoveRequiredItems(Shipyard shipyard) } character.Inventory.Bag.ConsumeItem(ItemTaskType.Shipyard, designId, 1, null); - character.SubtractMoney(SlotType.Inventory, (int)moneyOwed, ItemTaskType.Shipyard); + character.SubtractMoney(SlotType.Bag, (int)moneyOwed, ItemTaskType.Shipyard); return true; } diff --git a/AAEmu.Game/Core/Managers/SkillManager.cs b/AAEmu.Game/Core/Managers/SkillManager.cs index 72ddc3a293..c1f9f18efd 100644 --- a/AAEmu.Game/Core/Managers/SkillManager.cs +++ b/AAEmu.Game/Core/Managers/SkillManager.cs @@ -313,6 +313,7 @@ public void Load() _effects.Add("SkillController", new Dictionary()); // missing from the effect table _effects.Add("SpawnFishEffect", new Dictionary()); // missing from the effect table _effects.Add("ResetAoeDiminishingEffect", new Dictionary()); // missing from the effect table + _effects.Add("MoveToLocationEffect", new Dictionary()); // missing from the effect table _buffs = new Dictionary(); // TODO @@ -1359,6 +1360,22 @@ public void Load() } } + using (var command = connection.CreateCommand()) + { + command.CommandText = "SELECT * FROM move_to_location_effects"; + command.Prepare(); + using (var reader = new SQLiteWrapperReader(command.ExecuteReader())) + { + while (reader.Read()) + { + var template = new MoveToLocationEffect(); + template.Id = reader.GetUInt32("id"); + template.OwnHouseOnly = reader.GetBoolean("own_house_only", true); + _effects["MoveToLocationEffect"].Add(template.Id, template); + } + } + } + using (var command = connection.CreateCommand()) { command.CommandText = "SELECT * FROM restore_mana_effects"; diff --git a/AAEmu.Game/Core/Managers/SlaveManager.cs b/AAEmu.Game/Core/Managers/SlaveManager.cs index f93c051842..295274e1f9 100644 --- a/AAEmu.Game/Core/Managers/SlaveManager.cs +++ b/AAEmu.Game/Core/Managers/SlaveManager.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Numerics; +using System.Text.RegularExpressions; using AAEmu.Commons.IO; using AAEmu.Commons.Utils; @@ -13,6 +14,7 @@ using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Network.Connections; using AAEmu.Game.Core.Packets.G2C; +using AAEmu.Game.Models; using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.DoodadObj; using AAEmu.Game.Models.Game.DoodadObj.Static; @@ -41,6 +43,8 @@ namespace AAEmu.Game.Core.Managers; public class SlaveManager : Singleton { private static Logger Logger { get; } = LogManager.GetCurrentClassLogger(); + private Regex _nameRegex; + private Dictionary _slaveTemplates; //private Dictionary _activeSlaves; // смотри _slaves в WorldManager //private List _testSlaves; // смотри _slaves в WorldManager @@ -397,7 +401,6 @@ public void BindSlave(Character character, uint objId, AttachPointKind attachPoi // Check if the target spot is already taken var slave = GetSlaveByObjId(objId); - //var slave = GetActiveSlaveByObjId(objId); if (slave == null || slave.AttachedCharacters.ContainsKey(attachPoint)) return; @@ -720,10 +723,10 @@ public Slave Create(Character owner, SlaveSpawner useSpawner, uint templateId, I summonedSlave.TlId = tlId; summonedSlave.ObjId = objId; summonedSlave.TemplateId = slaveTemplate.Id; - summonedSlave.Name = string.IsNullOrWhiteSpace(slaveName) ? slaveTemplate.Name : slaveName; + var name = LocalizationManager.Instance.Get("slaves", "name", slaveTemplate.Id, slaveTemplate.Name); + summonedSlave.Name = string.IsNullOrWhiteSpace(slaveName) ? name : slaveName; summonedSlave.Level = (byte)slaveTemplate.Level; summonedSlave.ModelId = slaveTemplate.ModelId; - summonedSlave.Name = LocalizationManager.Instance.Get("slaves", "name", slaveTemplate.Id, slaveTemplate.Name); summonedSlave.Template = slaveTemplate; summonedSlave.Hp = slaveHp; summonedSlave.Mp = slaveMp; @@ -750,7 +753,7 @@ public Slave Create(Character owner, SlaveSpawner useSpawner, uint templateId, I // TODO: Load Gear if (owner != null) { - summonedSlave.Equipment = ItemManager.Instance.GetItemContainerForCharacter(owner.Id, SlotType.EquipmentSlave, summonedSlave, summonedSlave.Id); + summonedSlave.Equipment = ItemManager.Instance.GetItemContainerForCharacter(owner.Id, SlotType.SlaveEquipment, summonedSlave, summonedSlave.Id); } // Equip it's default items @@ -762,7 +765,7 @@ public Slave Create(Character owner, SlaveSpawner useSpawner, uint templateId, I foreach (var initialItem in itemPack) { var newItem = ItemManager.Instance.Create(initialItem.ItemId, 1, 0); - newItem.SlotType = SlotType.EquipmentSlave; + newItem.SlotType = SlotType.SlaveEquipment; newItem.Slot = initialItem.EquipSlotId; newItem.ItemFlags = ItemFlag.SoulBound; // связанный newItem.ChargeUseSkillTime = DateTime.UtcNow; @@ -1421,7 +1424,7 @@ private void SpawnPersistentSlaves(Character owner, Slave summonedSlave) } // Spawn Slave's slaves - private void SpawnSlaveSlaves(Character owner, SlaveBindings slaveBinding, Slave summonedSlave) + public void SpawnSlaveSlaves(Character owner, SlaveBindings slaveBinding, Slave summonedSlave) { if (slaveBinding.OwnerType != "Slave") return; @@ -1534,7 +1537,12 @@ public void CreateSlaveDoodads(Character owner, Item item, Slave summonedSlave, doodad.ParentObj = summonedSlave; doodad.Faction = summonedSlave.Faction; doodad.Type2 = 1u; // Flag: No idea why it's 1 for slave's doodads, seems to be 0 for everything else - doodad.Spawner = null; + //doodad.Spawner = null; + doodad.Spawner = new DoodadSpawner(); + doodad.Spawner.Id = 0; + doodad.Spawner.UnitId = doodad.TemplateId; + doodad.Spawner.Position = doodad.Transform.CloneAsSpawnPosition(); + doodad.SetScale(doodadBinding.Scale); @@ -1689,6 +1697,7 @@ public void LoadAdditionalData() /// public void Load() { + _nameRegex = new Regex(AppConfiguration.Instance.CharacterNameRegex, RegexOptions.Compiled); _slaveListLock = new object(); _slaveTemplates = new Dictionary(); _slaveInitialItems = new Dictionary>(); @@ -2361,4 +2370,28 @@ private bool DeleteSlaveById(MySqlConnection connection, MySqlTransaction transa return true; } + + public Slave RenameSlave(GameConnection connection, uint tlId, string newName) + { + var owner = connection.ActiveChar; + + var mySlave = GetSlaveByTlId(tlId); + + if (string.IsNullOrWhiteSpace(newName) || newName.Length == 0 || !_nameRegex.IsMatch(newName)) + { + Logger.Warn($"{owner.Name} The slave's name must not be the same as the character's name!"); + return null; + } + + if (mySlave == null || mySlave.TlId != tlId) + { + Logger.Warn($"{owner.Name} no slave active!"); + return null; + } + + mySlave.Name = newName.NormalizeName(); + owner.BroadcastPacket(new SCUnitNameChangedPacket(mySlave.ObjId, newName), true); + + return mySlave; + } } diff --git a/AAEmu.Game/Core/Managers/Stream/UccManager.cs b/AAEmu.Game/Core/Managers/Stream/UccManager.cs index a11937e87e..cfa5a12fbe 100644 --- a/AAEmu.Game/Core/Managers/Stream/UccManager.cs +++ b/AAEmu.Game/Core/Managers/Stream/UccManager.cs @@ -344,19 +344,19 @@ public void ConfirmDefaultUcc(StreamConnection connection) var character = connection.GameConnection.ActiveChar; - connection.GameConnection.ActiveChar.ChangeMoney(SlotType.Inventory, -50000); + connection.GameConnection.ActiveChar.ChangeMoney(SlotType.Bag, -50000); var newItem = (UccItem)ItemManager.Instance.Create(Item.CrestInk, 1, 0, true); // Crest Ink newItem.UccId = id; Save(ucc); - character.Inventory.Bag.AddOrMoveExistingItem(ItemTaskType.GainItemWithUcc, newItem); + character.Inventory.Bag.AddOrMoveExistingItem(ItemTaskType.CreateOriginUcc, newItem); } public static void CreateStamp(Character player, Item sourceInk) { var newItem = ItemManager.Instance.Create(Item.CrestStamp, 1, 0, true); // Crest Stamp newItem.UccId = sourceInk.UccId; - player.Inventory.Bag.AddOrMoveExistingItem(ItemTaskType.GainItemWithUcc, newItem); + player.Inventory.Bag.AddOrMoveExistingItem(ItemTaskType.CreateOriginUcc, newItem); } public static void ApplyStamp(Item stamp, Item targetItem) diff --git a/AAEmu.Game/Core/Managers/TimedRewardsManager.cs b/AAEmu.Game/Core/Managers/TimedRewardsManager.cs index 0eaa9ed643..02a83dbc35 100644 --- a/AAEmu.Game/Core/Managers/TimedRewardsManager.cs +++ b/AAEmu.Game/Core/Managers/TimedRewardsManager.cs @@ -4,6 +4,7 @@ using AAEmu.Game.Core.Network.Connections; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models; +using AAEmu.Game.Models.Game; using AAEmu.Game.Models.Tasks.TimedRewards; namespace AAEmu.Game.Core.Managers; @@ -98,7 +99,30 @@ public void DoDailyAccountLogin(ulong accountId) if (AppConfiguration.Instance.Loyalty.DailyLogin > 0) AccountManager.Instance.AddLoyalty(accountId, AppConfiguration.Instance.Loyalty.DailyLogin); - AccountManager.Instance.UpdateDivineClock(accountId, 0, 0); + DoDailyAccountDivineClockLogin(accountId); + } + + public void DoDailyAccountDivineClockLogin(ulong accountId) + { + // TODO add initialization of ScheduleItem items for Divine Clock + // delete existing entries + AccountManager.Instance.DeleteDivineClockEntries(accountId); + // create new entries + var li = GameScheduleManager.Instance.GetMatchingPeriods(); + if (li == null) { return; } + + foreach (var scheduleItemId in li) + { + var si = new ScheduleItem + { + ScheduleItemId = scheduleItemId, + Gave = 0, + Cumulated = 0, + Updated = DateTime.UtcNow + }; + // Update Account Divine Clock time + AccountManager.Instance.UpdateDivineClock(accountId, si.ScheduleItemId, si.Cumulated, si.Gave); + } } public void AddOfflineLabor(GameConnection connection, DateTime lastLoginTime, short currentLabor) diff --git a/AAEmu.Game/Core/Managers/TradeManager.cs b/AAEmu.Game/Core/Managers/TradeManager.cs index d39a29b48d..78ee82fe8d 100644 --- a/AAEmu.Game/Core/Managers/TradeManager.cs +++ b/AAEmu.Game/Core/Managers/TradeManager.cs @@ -302,8 +302,8 @@ public void OkTrade(Character character) if (_trades[tradeId].OkOwner && _trades[tradeId].OkTarget) { // Check inventory space - if (owner.Inventory.FreeSlotCount(SlotType.Inventory) < _trades[tradeId].TargetItems.Count) CancelTrade(owner.ObjId, 0, tradeId); - if (target.Inventory.FreeSlotCount(SlotType.Inventory) < _trades[tradeId].OwnerItems.Count) CancelTrade(target.ObjId, 0, tradeId); + if (owner.Inventory.FreeSlotCount(SlotType.Bag) < _trades[tradeId].TargetItems.Count) CancelTrade(owner.ObjId, 0, tradeId); + if (target.Inventory.FreeSlotCount(SlotType.Bag) < _trades[tradeId].OwnerItems.Count) CancelTrade(target.ObjId, 0, tradeId); // Finish trade FinishTrade(owner, target, tradeId); diff --git a/AAEmu.Game/Core/Managers/UnitManagers/CharacterManager.cs b/AAEmu.Game/Core/Managers/UnitManagers/CharacterManager.cs index b8a8e7d9b5..047cdb6c43 100644 --- a/AAEmu.Game/Core/Managers/UnitManagers/CharacterManager.cs +++ b/AAEmu.Game/Core/Managers/UnitManagers/CharacterManager.cs @@ -12,6 +12,7 @@ using AAEmu.Game.Core.Network.Connections; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models; +using AAEmu.Game.Models.Game; using AAEmu.Game.Models.Game.Attendance; using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Char.Templates; @@ -336,7 +337,7 @@ public void Load() { var template = new ActabilityTemplate(); template.Id = reader.GetUInt32("id"); - template.IconId = reader.GetUInt32("icon_id", 0); + //template.IconId = reader.GetUInt32("icon_id", 0); template.Name = reader.GetString("name"); template.SkillPageVisible = reader.GetBoolean("skill_page_visible"); template.UnitAttributeId = reader.GetInt32("unit_attr_id"); @@ -902,7 +903,7 @@ public static void ApplyBeautySalon(Character character, uint hairModel, UnitCus { // TODO: Add support for future X-day Salon Certificate items - if (character.Inventory.GetItemsCount(SlotType.Inventory, Item.SalonCertificate) <= 0) + if (character.Inventory.GetItemsCount(SlotType.Bag, Item.SalonCertificate) <= 0) return; var oldHair = character.Equipment.GetItemBySlot((byte)EquipmentItemSlot.Hair); diff --git a/AAEmu.Game/Core/Managers/UnitManagers/DoodadManager.cs b/AAEmu.Game/Core/Managers/UnitManagers/DoodadManager.cs index ae9afc5145..084be120be 100644 --- a/AAEmu.Game/Core/Managers/UnitManagers/DoodadManager.cs +++ b/AAEmu.Game/Core/Managers/UnitManagers/DoodadManager.cs @@ -692,6 +692,7 @@ public void Load() // doodad_func_consume_changer_items // This is not actually a phase, but rather a collection of items that is available for doodad_func_consume_changers + // TODO there is no such table in 5070 AAFree //using (var command = connection.CreateCommand()) //{ // command.CommandText = "SELECT * FROM doodad_func_consume_changer_items"; @@ -712,6 +713,7 @@ public void Load() //} //// doodad_func_consume_changer_model_items + // TODO there is no such table in 5070 AAFree //using (var command = connection.CreateCommand()) //{ // command.CommandText = "SELECT * FROM doodad_func_consume_changer_model_items"; @@ -3127,7 +3129,7 @@ public static Doodad CreatePlayerDoodad(Character character, uint id, float x, f foreach (var item in items) { character.ItemUse(preferredItem); - character.Inventory.ConsumeItem(new[] { SlotType.Inventory }, ItemTaskType.DoodadCreate, item, 1, + character.Inventory.ConsumeItem(new[] { SlotType.Bag }, ItemTaskType.DoodadCreate, item, 1, preferredItem); } diff --git a/AAEmu.Game/Core/Managers/UnitManagers/NpcManager.cs b/AAEmu.Game/Core/Managers/UnitManagers/NpcManager.cs index a21ef7c3cf..a5dcf375b4 100644 --- a/AAEmu.Game/Core/Managers/UnitManagers/NpcManager.cs +++ b/AAEmu.Game/Core/Managers/UnitManagers/NpcManager.cs @@ -526,7 +526,14 @@ public void Load() template.CharRaceId = reader.GetInt32("char_race_id"); template.NpcGradeId = (NpcGradeType)reader.GetByte("npc_grade_id"); template.NpcKindId = (NpcKindType)reader.GetByte("npc_kind_id"); - //template.Level = reader.GetByte("level"); + try + { + template.Level = reader.GetByte("level"); // TODO у Npc TemplateId=16688 Level = 555 ! + } + catch (Exception) + { + template.Level = 55; + } template.NpcTemplateId = (NpcTemplateType)reader.GetByte("npc_template_id"); template.ModelId = reader.GetUInt32("model_id"); template.FactionId = (FactionsEnum)reader.GetUInt32("faction_id"); diff --git a/AAEmu.Game/Core/Managers/World/SpecialtyManager.cs b/AAEmu.Game/Core/Managers/World/SpecialtyManager.cs index 6747cf63e3..efa77d40e1 100644 --- a/AAEmu.Game/Core/Managers/World/SpecialtyManager.cs +++ b/AAEmu.Game/Core/Managers/World/SpecialtyManager.cs @@ -91,7 +91,7 @@ public void Load() } else { - Logger.Warn($"Дубликат обнаружен в _specialtyBundleItems: id={template.Id}"); + Logger.Warn($"Duplicate found in _specialtyBundleItems: id={template.Id}"); } // Проверка на дубликат в _specialtyBundleItemsMapped @@ -104,7 +104,7 @@ public void Load() } else { - Logger.Warn($"Дубликат обнаружен в _specialtyBundleItemsMapped: itemId={template.ItemId}, specialtyBundleId={template.SpecialtyBundleId}"); + Logger.Warn($"Duplicate found in _specialtyBundleItemsMapped: itemId={template.ItemId}, specialtyBundleId={template.SpecialtyBundleId}"); } } } diff --git a/AAEmu.Game/Core/Managers/World/WorldManager.cs b/AAEmu.Game/Core/Managers/World/WorldManager.cs index e3b990d905..85503e26b4 100644 --- a/AAEmu.Game/Core/Managers/World/WorldManager.cs +++ b/AAEmu.Game/Core/Managers/World/WorldManager.cs @@ -304,20 +304,24 @@ public void Load() while (reader.Read()) { var idz = new IndunZone(); - idz.ZoneGroupId = reader.GetUInt32("zone_group_id"); + idz.ZoneGroupId = reader.GetUInt16("zone_group_id"); + idz.ClientDriven = reader.GetBoolean("client_driven"); + idz.Duel = reader.GetBoolean("duel"); + idz.EnterCount = reader.GetUInt32("enter_count"); + idz.ExpPanelty = reader.GetBoolean("exp_panelty"); + idz.HasGraveyard = reader.GetBoolean("has_graveyard"); + idz.ItemId = reader.IsDBNull("item_id") ? 0 : reader.GetUInt32("item_id"); //idz.Name = reader.GetString("name"); //idz.Comment = reader.GetString("comment"); - idz.LevelMin = reader.GetUInt32("level_min"); idz.LevelMax = reader.GetUInt32("level_max"); + idz.LevelMin = reader.GetUInt32("level_min"); idz.MaxPlayers = reader.GetUInt32("max_players"); + //idz.Option = reader.GetString("option"); + idz.PartyOnly = reader.GetBoolean("party_only"); idz.PvP = reader.GetBoolean("pvp"); - idz.HasGraveyard = reader.GetBoolean("has_graveyard"); - idz.ItemId = reader.IsDBNull("item_id") ? 0 : reader.GetUInt32("item_id"); idz.RestoreItemTime = reader.GetUInt32("restore_item_time"); - idz.PartyOnly = reader.GetBoolean("party_only"); - idz.ClientDriven = reader.GetBoolean("client_driven"); idz.SelectChannel = reader.GetBoolean("select_channel"); - idz.LocalizedName = LocalizationManager.Instance.Get("indun_zones", "name", idz.ZoneGroupId, idz.Name); + //idz.LocalizedName = LocalizationManager.Instance.Get("indun_zones", "name", idz.ZoneGroupId, idz.Name); if (!_indunZones.TryAdd(idz.ZoneGroupId, idz)) Logger.Fatal($"Unable to add zone_group_id: {idz.ZoneGroupId} from indun_zone"); diff --git a/AAEmu.Game/Core/Managers/World/ZoneManager.cs b/AAEmu.Game/Core/Managers/World/ZoneManager.cs index 4726208bcf..c8a17e56fa 100644 --- a/AAEmu.Game/Core/Managers/World/ZoneManager.cs +++ b/AAEmu.Game/Core/Managers/World/ZoneManager.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Numerics; @@ -129,7 +130,16 @@ public void Load() { while (reader.Read()) { - var zoneGroupId = reader.GetUInt16("zone_group_id"); + ushort zoneGroupId; // AAFree добавили остров zoneGroupId = 9000001; + try + { + zoneGroupId = reader.GetUInt16("zone_group_id"); + } + catch (Exception) + { + continue; + } + if (_groups.ContainsKey(zoneGroupId)) { var template = new ZoneConflict(_groups[zoneGroupId]); diff --git a/AAEmu.Game/Core/Network/Game/GameNetwork.cs b/AAEmu.Game/Core/Network/Game/GameNetwork.cs index 256988387c..5721189477 100644 --- a/AAEmu.Game/Core/Network/Game/GameNetwork.cs +++ b/AAEmu.Game/Core/Network/Game/GameNetwork.cs @@ -23,8 +23,8 @@ private GameNetwork() // World RegisterPacket(CSOffsets.X2EnterWorldPacket, 1, typeof(X2EnterWorldPacket)); // level = 1 - // double _01_&_05_ - // пакет для дешифрации + // double _01_&_05_ + // пакет для дешифрации RegisterPacket(CSOffsets.CSAesXorKeyPacket, 1, typeof(CSAesXorKeyPacket)); // level = 1 RegisterPacket(CSOffsets.CSAesXorKey_05_Packet, 5, typeof(CSAesXorKey_05_Packet)); // level = 5 // @@ -41,10 +41,10 @@ private GameNetwork() RegisterPacket(CSOffsets.CSRequestCommonFarmListPacket, 5, typeof(CSRequestCommonFarmListPacket)); RegisterPacket(CSOffsets.CSChallengeDuelPacket, 5, typeof(CSChallengeDuelPacket)); RegisterPacket(CSOffsets.CSStartDuelPacket, 5, typeof(CSStartDuelPacket)); - //RegisterPacket(CSOffsets.CSHeroRankingListPacket, 5, typeof(CSHeroRankingListPacket)); - //RegisterPacket(CSOffsets.CSHeroCandidateListPacket, 5, typeof(CSHeroCandidateListPacket)); - //RegisterPacket(CSOffsets.CSHeroAbstainPacket, 5, typeof(CSHeroAbstainPacket)); - //RegisterPacket(CSOffsets.CSHeroVotingPacket, 5, typeof(CSHeroVotingPacket)); + RegisterPacket(CSOffsets.CSHeroRankingListPacket, 5, typeof(CSHeroRankingListPacket)); + RegisterPacket(CSOffsets.CSHeroCandidateListPacket, 5, typeof(CSHeroCandidateListPacket)); + RegisterPacket(CSOffsets.CSHeroAbstainPacket, 5, typeof(CSHeroAbstainPacket)); + RegisterPacket(CSOffsets.CSHeroVotingPacket, 5, typeof(CSHeroVotingPacket)); RegisterPacket(CSOffsets.CSConvertItemLookPacket, 5, typeof(CSConvertItemLookPacket)); //RegisterPacket(CSOffsets.CSConvertItemLook2Packet, 5, typeof(CSConvertItemLook2Packet)); RegisterPacket(CSOffsets.CSSetPingPosPacket, 5, typeof(CSSetPingPosPacket)); @@ -67,14 +67,14 @@ private GameNetwork() //RegisterPacket(CSOffsets.CSUnknown0x0cbPacket, 5, typeof(CSUnknown0x0cbPacket)); //RegisterPacket(CSOffsets.CSUnknown0x0aPacket, 5, typeof(CSUnknown0x0aPacket)); RegisterPacket(CSOffsets.CSChangeMateNamePacket, 5, typeof(CSChangeMateNamePacket)); - //RegisterPacket(CSOffsets.CSSendNationMemberCountListPacket, 5, typeof(CSSendNationMemberCountListPacket)); + RegisterPacket(CSOffsets.CSSendNationMemberCountListPacket, 5, typeof(CSSendNationMemberCountListPacket)); RegisterPacket(CSOffsets.CSNationSendExpeditionImmigrationAcceptRejectPacket, 5, typeof(CSNationSendExpeditionImmigrationAcceptRejectPacket)); - //RegisterPacket(CSOffsets.CSSendExpeditionImmigrationListPacket, 5, typeof(CSSendExpeditionImmigrationListPacket)); - //RegisterPacket(CSOffsets.CSSendRelationFriendPacket, 5, typeof(CSSendRelationFriendPacket)); - //RegisterPacket(CSOffsets.CSSendRelationVotePacket, 5, typeof(CSSendRelationVotePacket)); - //RegisterPacket(CSOffsets.CSSendNationInfoSetPacket, 5, typeof(CSSendNationInfoSetPacket)); + RegisterPacket(CSOffsets.CSSendExpeditionImmigrationListPacket, 5, typeof(CSSendExpeditionImmigrationListPacket)); + RegisterPacket(CSOffsets.CSSendRelationFriendPacket, 5, typeof(CSSendRelationFriendPacket)); + RegisterPacket(CSOffsets.CSSendRelationVotePacket, 5, typeof(CSSendRelationVotePacket)); + RegisterPacket(CSOffsets.CSSendNationInfoSetPacket, 5, typeof(CSSendNationInfoSetPacket)); RegisterPacket(CSOffsets.CSRankCharacterPacket, 5, typeof(CSRankCharacterPacket)); - //RegisterPacket(CSOffsets.CSRankSnapshotPacket, 5, typeof(CSRankSnapshotPacket)); + RegisterPacket(CSOffsets.CSRankSnapshotPacket, 5, typeof(CSRankSnapshotPacket)); RegisterPacket(CSOffsets.CSHeroRequestRankDataPacket, 5, typeof(CSHeroRequestRankDataPacket)); //RegisterPacket(CSOffsets.CSGetRankerInformationPacket, 5, typeof(CSGetRankerInformationPacket)); //RegisterPacket(CSOffsets.CSRequestRankerAppearancePacket, 5, typeof(CSRequestRankerAppearancePacket)); @@ -89,11 +89,11 @@ private GameNetwork() RegisterPacket(CSOffsets.CSJurySummonedPacket, 5, typeof(CSJurySummonedPacket)); RegisterPacket(CSOffsets.CSJuryEndTestimonyPacket, 5, typeof(CSJuryEndTestimonyPacket)); RegisterPacket(CSOffsets.CSCancelTrialPacket, 5, typeof(CSCancelTrialPacket)); - //RegisterPacket(CSOffsets.CSJurySentencePacket, 5, typeof(CSJurySentencePacket)); + RegisterPacket(CSOffsets.CSJurySentencePacket, 5, typeof(CSJurySentencePacket)); RegisterPacket(CSOffsets.CSReportCrimePacket, 5, typeof(CSReportCrimePacket)); RegisterPacket(CSOffsets.CSRequestJuryWaitingNumberPacket, 5, typeof(CSRequestJuryWaitingNumberPacket)); - //RegisterPacket(CSOffsets.CSRequestSetBountyPacket, 5, typeof(CSRequestSetBountyPacket)); - //RegisterPacket(CSOffsets.CSUpdateBountyPacket, 5, typeof(CSUpdateBountyPacket)); + RegisterPacket(CSOffsets.CSRequestSetBountyPacket, 5, typeof(CSRequestSetBountyPacket)); + RegisterPacket(CSOffsets.CSUpdateBountyPacket, 5, typeof(CSUpdateBountyPacket)); //RegisterPacket(CSOffsets.CSTrialReportBadUserPacket, 5, typeof(CSTrialReportBadUserPacket)); //RegisterPacket(CSOffsets.CSTrialRequestBadUserListPacket, 5, typeof(CSTrialRequestBadUserListPacket)); //RegisterPacket(CSOffsets.CSsUnknown0x146Packet, 5, typeof(CSsUnknown0x146Packet)); @@ -109,15 +109,15 @@ private GameNetwork() RegisterPacket(CSOffsets.CSCancelLeaveWorldPacket, 5, typeof(CSCancelLeaveWorldPacket)); RegisterPacket(CSOffsets.CSRequestSpecialtyCurrentPacket, 5, typeof(CSRequestSpecialtyCurrentPacket)); RegisterPacket(CSOffsets.CSIdleStatusPacket, 5, typeof(CSIdleStatusPacket)); - //RegisterPacket(CSOffsets.CSChangeClientNpcTargetPacket, 5, typeof(CSChangeClientNpcTargetPacket)); + RegisterPacket(CSOffsets.CSChangeClientNpcTargetPacket, 5, typeof(CSChangeClientNpcTargetPacket)); RegisterPacket(CSOffsets.CSCompletedCinemaPacket, 5, typeof(CSCompletedCinemaPacket)); - //RegisterPacket(CSOffsets.CSCheckDemoModePacket, 5, typeof(CSCheckDemoModePacket)); - //RegisterPacket(CSOffsets.CSDemoCharResetPacket, 5, typeof(CSDemoCharResetPacket)); + RegisterPacket(CSOffsets.CSCheckDemoModePacket, 5, typeof(CSCheckDemoModePacket)); + RegisterPacket(CSOffsets.CSDemoCharResetPacket, 5, typeof(CSDemoCharResetPacket)); RegisterPacket(CSOffsets.CSConsoleCmdUsedPacket, 5, typeof(CSConsoleCmdUsedPacket)); RegisterPacket(CSOffsets.CSEditorGameModePacket, 5, typeof(CSEditorGameModePacket)); RegisterPacket(CSOffsets.CSTeleportEndedPacket, 5, typeof(CSTeleportEndedPacket)); - //RegisterPacket(CSOffsets.CSInteractGimmickPacket, 5, typeof(CSInteractGimmickPacket)); - //RegisterPacket(CSOffsets.CSWorldRaycastingPacket, 5, typeof(CSWorldRaycastingPacket)); + RegisterPacket(CSOffsets.CSInteractGimmickPacket, 5, typeof(CSInteractGimmickPacket)); + RegisterPacket(CSOffsets.CSWorldRaycastingPacket, 5, typeof(CSWorldRaycastingPacket)); RegisterPacket(CSOffsets.CSOpenExpeditionImmigrationRequestPacket, 5, typeof(CSOpenExpeditionImmigrationRequestPacket)); RegisterPacket(CSOffsets.CSNationGetNationNamePacket, 5, typeof(CSNationGetNationNamePacket)); RegisterPacket(CSOffsets.CSRefreshInCharacterListPacket, 5, typeof(CSRefreshInCharacterListPacket)); @@ -154,8 +154,8 @@ private GameNetwork() RegisterPacket(CSOffsets.CSSecurityReportPacket, 5, typeof(CSSecurityReportPacket)); RegisterPacket(CSOffsets.CSEnprotectStubCallResponsePacket, 5, typeof(CSEnprotectStubCallResponsePacket)); RegisterPacket(CSOffsets.CSRepresentCharacterPacket, 5, typeof(CSRepresentCharacterPacket)); - //RegisterPacket(CSOffsets.CSPacketUnknown0x0aaPacket, 5, typeof(CSPacketUnknown0x0aaPacket)); - RegisterPacket(CSOffsets.CSCheckDemoModePacket, 5, typeof(CSCheckDemoModePacket)); + //RegisterPacket(CSOffsets.off_39E9A31C, 5, typeof(off_39E9A31C)); + RegisterPacket(CSOffsets.CSStoppedCinemaPacket, 5, typeof(CSStoppedCinemaPacket)); RegisterPacket(CSOffsets.CSCreateCharacterPacket, 5, typeof(CSCreateCharacterPacket)); RegisterPacket(CSOffsets.CSEditCharacterPacket, 5, typeof(CSEditCharacterPacket)); RegisterPacket(CSOffsets.CSBroadcastVisualOption_0_Packet, 5, typeof(CSBroadcastVisualOption_0_Packet)); @@ -239,7 +239,7 @@ private GameNetwork() RegisterPacket(CSOffsets.CSChangeHouseNamePacket, 5, typeof(CSChangeHouseNamePacket)); RegisterPacket(CSOffsets.CSChangeHousePermissionPacket, 5, typeof(CSChangeHousePermissionPacket)); RegisterPacket(CSOffsets.CSRequestHouseTaxPacket, 5, typeof(CSRequestHouseTaxPacket)); - RegisterPacket(CSOffsets.CSPerpayHouseTaxPacket, 5, typeof(CSPerpayHouseTaxPacket)); + RegisterPacket(CSOffsets.CSPrepayHouseTaxPacket, 5, typeof(CSPrepayHouseTaxPacket)); RegisterPacket(CSOffsets.CSAllowRecoverPacket, 5, typeof(CSAllowHousingRecoverPacket)); // CSAllowRecoverPacket RegisterPacket(CSOffsets.CSSellHouseCancelPacket, 5, typeof(CSSellHouseCancelPacket)); RegisterPacket(CSOffsets.CSDecorateHousePacket, 5, typeof(CSDecorateHousePacket)); @@ -255,6 +255,7 @@ private GameNetwork() RegisterPacket(CSOffsets.CSBindSlavePacket, 5, typeof(CSBindSlavePacket)); RegisterPacket(CSOffsets.CSDiscardSlavePacket, 5, typeof(CSDiscardSlavePacket)); RegisterPacket(CSOffsets.CSBoardingTransferPacket, 5, typeof(CSBoardingTransferPacket)); + RegisterPacket(CSOffsets.CSRemoveAllFieldSlavesPacket, 5, typeof(CSRemoveAllFieldSlavesPacket)); RegisterPacket(CSOffsets.CSTurretStatePacket, 5, typeof(CSTurretStatePacket)); RegisterPacket(CSOffsets.CSCreateSkillControllerPacket, 5, typeof(CSCreateSkillControllerPacket)); RegisterPacket(CSOffsets.CSJoinTrialAudiencePacket, 5, typeof(CSJoinTrialAudiencePacket)); @@ -350,14 +351,15 @@ private GameNetwork() //RegisterPacket(CSOffsets.CSRefreshBotCheckInfoPacket, 5, typeof(CSRefreshBotCheckInfoPacket)); //RegisterPacket(CSOffsets.CSAnswerBotCheckPacket, 5, typeof(CSAnswerBotCheckPacket)); RegisterPacket(CSOffsets.CSChangeSlaveNamePacket, 5, typeof(CSChangeSlaveNamePacket)); + RegisterPacket(CSOffsets.CSSearchListPacket, 5, typeof(CSSearchListPacket)); RegisterPacket(CSOffsets.CSUseTeleportPacket, 5, typeof(CSUseTeleportPacket)); RegisterPacket(CSOffsets.CSAuctionPostPacket, 5, typeof(CSAuctionPostPacket)); RegisterPacket(CSOffsets.CSAuctionSearchPacket, 5, typeof(CSAuctionSearchPacket)); RegisterPacket(CSOffsets.CSAuctionMyBidListPacket, 5, typeof(CSAuctionMyBidListPacket)); RegisterPacket(CSOffsets.CSAuctionLowestPricePacket, 5, typeof(CSAuctionLowestPricePacket)); - //RegisterPacket(CSOffsets.CSAuctionSearchSoldRecordPacket, 5, typeof(CSAuctionSearchSoldRecordPacket)); - //RegisterPacket(CSOffsets.CSAuctionCancelPacket, 5, typeof(CSAuctionCancelPacket)); - //RegisterPacket(CSOffsets.CSAuctionBidPacket, 5, typeof(CSAuctionBidPacket)); + RegisterPacket(CSOffsets.CSAuctionSearchSoldRecordPacket, 5, typeof(CSAuctionSearchSoldRecordPacket)); + RegisterPacket(CSOffsets.CSAuctionCancelPacket, 5, typeof(CSAuctionCancelPacket)); + RegisterPacket(CSOffsets.CSAuctionBidPacket, 5, typeof(CSAuctionBidPacket)); RegisterPacket(CSOffsets.CSExecuteCraftPacket, 5, typeof(CSExecuteCraftPacket)); RegisterPacket(CSOffsets.CSSetLpManageCharacterPacket, 5, typeof(CSSetLpManageCharacterPacket)); RegisterPacket(CSOffsets.CSSetCraftingPayPacket, 5, typeof(CSSetCraftingPayPacket)); @@ -375,9 +377,9 @@ private GameNetwork() RegisterPacket(CSOffsets.CSEquipmentsUnsecurePacket, 5, typeof(CSEquipmentsUnsecurePacket)); RegisterPacket(CSOffsets.CSRepairSingleEquipmentPacket, 5, typeof(CSRepairSingleEquipmentPacket)); RegisterPacket(CSOffsets.CSRepairAllEquipmentsPacket, 5, typeof(CSRepairAllEquipmentsPacket)); - //RegisterPacket(CSOffsets.CSChangeAutoUseAAPointPacket, 5, typeof(CSChangeAutoUseAAPointPacket)); + RegisterPacket(CSOffsets.CSChangeAutoUseAaPointPacket, 5, typeof(CSChangeAutoUseAaPointPacket)); RegisterPacket(CSOffsets.CSThisTimeUnpackPacket, 5, typeof(CSThisTimeUnpackItemPacket)); - //RegisterPacket(CSOffsets.CSTakeScheduleItemPacket, 5, typeof(CSTakeScheduleItemPacket)); + RegisterPacket(CSOffsets.CSTakeScheduleItemPacket, 5, typeof(CSTakeScheduleItemPacket)); RegisterPacket(CSOffsets.CSChangeMateEquipmentPacket, 5, typeof(CSChangeMateEquipmentPacket)); RegisterPacket(CSOffsets.CSChangeSlaveEquipmentPacket, 5, typeof(CSChangeSlaveEquipmentPacket)); //RegisterPacket(CSOffsets.CSLoginUccItemsPacket, 5, typeof(CSLoginUccItemsPacket)); diff --git a/AAEmu.Game/Core/Network/Game/GamePacket.cs b/AAEmu.Game/Core/Network/Game/GamePacket.cs index 58ce532bed..c4320e8534 100644 --- a/AAEmu.Game/Core/Network/Game/GamePacket.cs +++ b/AAEmu.Game/Core/Network/Game/GamePacket.cs @@ -178,9 +178,10 @@ public override PacketBase Decode(PacketStream ps) } catch (Exception ex) { + EncryptionManager.needNewkey1 = true; Logger.Error($"GamePacket: C->S type {TypeId:X3} {ToString()?.Substring(23)}{Verbose()}"); Logger.Fatal(ex); - throw; + //throw; } return this; diff --git a/AAEmu.Game/Core/Network/Game/GameProtocolHandler.cs b/AAEmu.Game/Core/Network/Game/GameProtocolHandler.cs index 005841f5d2..ac338a5b04 100644 --- a/AAEmu.Game/Core/Network/Game/GameProtocolHandler.cs +++ b/AAEmu.Game/Core/Network/Game/GameProtocolHandler.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Concurrent; -using System.IO; using System.Text; + using AAEmu.Commons.Cryptography; using AAEmu.Commons.Exceptions; using AAEmu.Commons.Network; using AAEmu.Commons.Network.Core; -using AAEmu.Commons.Utils; using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Network.Connections; + using NLog; namespace AAEmu.Game.Core.Network.Game; @@ -28,6 +28,8 @@ public GameProtocolHandler() _packets.TryAdd(4, new ConcurrentDictionary()); // deflate _packets.TryAdd(5, new ConcurrentDictionary()); // encrypt _packets.TryAdd(6, new ConcurrentDictionary()); // encrypt + EncryptionManager.needNewkey1 = false; + EncryptionManager.needNewkey2 = false; } public override void OnConnect(ISession session) @@ -121,6 +123,7 @@ public void OnReceive(GameConnection connection, byte[] buf, int offset, int byt stream.Rollback(); connection.LastPacket = stream; stream = null; + EncryptionManager.needNewkey1 = true; continue; } var packetLen = len + stream.Pos; @@ -214,5 +217,9 @@ private static void HandleUnknownPacket(GameConnection connection, uint type, by for (var i = stream.Pos; i < stream.Count; i++) dump.AppendFormat("{0:x2} ", stream.Buffer[i]); Logger.Error("Unknown packet 0x{0:x2}({3}) from {1}:\n{2}", type, connection.Ip, dump, level); + if (type > 0x3ff) + { + EncryptionManager.needNewkey1 = true; + } } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSAuctionBidPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSAuctionBidPacket.cs index 71cca834d8..df5b8c9b97 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSAuctionBidPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSAuctionBidPacket.cs @@ -13,44 +13,17 @@ public CSAuctionBidPacket() : base(CSOffsets.CSAuctionBidPacket, 5) public override void Read(PacketStream stream) { - var npcObjId = stream.ReadBc(); - var npcObjId2 = stream.ReadBc(); + var auctioneerId = stream.ReadBc(); + var auctioneerId2 = stream.ReadBc(); - var auctionItem = new AuctionItem(); - auctionItem.Read(stream); + var display = new AuctionDisplay(); + display.Read(stream); - //var auctionId = stream.ReadUInt64(); - //var duration = stream.ReadByte(); - //var itemId = stream.ReadUInt32(); - //var objectId = stream.ReadUInt64(); - //var grade = stream.ReadByte(); - //var bound = stream.ReadByte(); - //var stackSize = stream.ReadUInt32(); - //var detailType = stream.ReadByte(); - //var creationTime = stream.ReadDateTime(); - //var lifeSpan = stream.ReadUInt32(); - //var type1 = stream.ReadUInt32(); - //var worldID = stream.ReadByte(); - //var unsecureTime = stream.ReadDateTime(); - //var unpackTime = stream.ReadDateTime(); - //var worldId2 = stream.ReadByte(); - //var type2 = stream.ReadUInt32(); - //var clientName = stream.ReadString(); - //var startMoney = stream.ReadUInt32(); - //var directMoney = stream.ReadUInt32(); - //var timeLeft = stream.ReadUInt64(); - //var bidWorld = stream.ReadByte(); - //var type3 = stream.ReadUInt32(); - //var bidderName = stream.ReadString(); - //var bidMoney = stream.ReadUInt32(); - //var extra = stream.ReadUInt32(); + var bid = new AuctionBid(); + bid.Read(stream); - var typeBid = stream.ReadUInt64(); - var biddingWorldID = stream.ReadByte(); - var typeBid2 = stream.ReadUInt32(); - var name = stream.ReadString(); - var bid = stream.ReadInt32(); + Logger.Warn($"AuctionBid, auctioneerId: {auctioneerId}, auctioneerId2: {auctioneerId2}, BidderName: {bid.BidderName}, LotId: {display.Lot.Id}:{bid.LotId}, Money: {bid.Money}"); - AuctionManager.Instance.BidOnAuctionItem(Connection.ActiveChar, auctionItem.Id, bid); + AuctionManager.Instance.BidOnAuctionLot(Connection.ActiveChar, auctioneerId, auctioneerId2, display.Lot, bid); } -} \ No newline at end of file +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSAuctionCancelPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSAuctionCancelPacket.cs index 9bf6ecb66d..f03c7f5329 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSAuctionCancelPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSAuctionCancelPacket.cs @@ -1,6 +1,7 @@ using AAEmu.Commons.Network; using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Network.Game; +using AAEmu.Game.Models.Game.Auction; namespace AAEmu.Game.Core.Packets.C2G; @@ -8,40 +9,19 @@ public class CSAuctionCancelPacket : GamePacket { public CSAuctionCancelPacket() : base(CSOffsets.CSAuctionCancelPacket, 5) { - } + } public override void Read(PacketStream stream) { - var npcObjId = stream.ReadBc(); - var npcObjId2 = stream.ReadBc(); + var auctioneerId = stream.ReadBc(); + var auctioneerId2 = stream.ReadBc(); - var auctionId = stream.ReadUInt64(); - var duration = stream.ReadByte(); - var itemId = stream.ReadUInt32(); - var objectId = stream.ReadUInt64(); - var grade = stream.ReadByte(); - var bound = stream.ReadByte(); - var stackSize = stream.ReadUInt32(); - var detailType = stream.ReadByte(); - var creationTime = stream.ReadDateTime(); - var lifeSpan = stream.ReadUInt32(); - var type1 = stream.ReadUInt32(); - var worldID = stream.ReadByte(); - var unsecureTime = stream.ReadDateTime(); - var unpackTime = stream.ReadDateTime(); - var worldId2 = stream.ReadByte(); - var type2 = stream.ReadUInt32(); - var clientName = stream.ReadString(); - var startMoney = stream.ReadUInt32(); - var directMoney = stream.ReadUInt32(); - var timeLeft = stream.ReadUInt64(); - var bidWorld = stream.ReadByte(); - var type3 = stream.ReadUInt32(); - var bidderName = stream.ReadString(); - var bidMoney = stream.ReadUInt32(); - var extra = stream.ReadUInt32(); - var player = Connection.ActiveChar; + var lot = new AuctionLot(); + //lot.Read(stream); + stream.Read(lot); - AuctionManager.Instance.CancelAuctionItem(player, auctionId); - } -} \ No newline at end of file + Logger.Warn($"AuctionCancel, auctioneerId: {auctioneerId}, auctioneerId2: {auctioneerId2}, ClientName: {lot.ClientName}, LotId: {lot.Id}"); + + AuctionManager.Instance.CancelAuctionLot(Connection.ActiveChar, lot.Id); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSAuctionLowestPricePacket.cs b/AAEmu.Game/Core/Packets/C2G/CSAuctionLowestPricePacket.cs index 66b4420918..7780d617e7 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSAuctionLowestPricePacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSAuctionLowestPricePacket.cs @@ -13,13 +13,13 @@ public CSAuctionLowestPricePacket() : base(CSOffsets.CSAuctionLowestPricePacket, public override void Read(PacketStream stream) { - var npcObjId = stream.ReadBc(); + var auctioneerId = stream.ReadBc(); + var auctioneerId2 = stream.ReadBc(); var itemTemplateId = stream.ReadUInt32(); var itemGrade = stream.ReadByte(); - var cheapestItem = AuctionManager.Instance.GetCheapestAuctionItem(itemTemplateId); - - Connection.ActiveChar.SendPacket(new SCAuctionLowestPricePacket(cheapestItem)); + Logger.Warn($"AuctionLowestPrice, auctioneerId: {auctioneerId}, auctioneerId2: {auctioneerId2}, TemplateId: {itemTemplateId}, Grade: {itemGrade}"); + AuctionManager.Instance.CheapestAuctionLot(Connection.ActiveChar, itemTemplateId, itemGrade); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSAuctionMyBidListPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSAuctionMyBidListPacket.cs index 08a1e759b8..4ce33e6d16 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSAuctionMyBidListPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSAuctionMyBidListPacket.cs @@ -1,4 +1,5 @@ using AAEmu.Commons.Network; +using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Network.Game; namespace AAEmu.Game.Core.Packets.C2G; @@ -11,9 +12,12 @@ public CSAuctionMyBidListPacket() : base(CSOffsets.CSAuctionMyBidListPacket, 5) public override void Read(PacketStream stream) { - var npcObjId = stream.ReadBc(); + var auctioneerId = stream.ReadBc(); + var auctioneerId2 = stream.ReadBc(); var page = stream.ReadInt32(); - Logger.Warn("AuctionMyBidList, NpcObjId: {0}, Page: {1}", npcObjId, page); + Logger.Warn($"AuctionMyBidList, auctioneerId: {auctioneerId}, auctioneerId2: {auctioneerId2}, Page: {page}"); + + AuctionManager.Instance.GetBidAuctionLots(Connection.ActiveChar, page); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSAuctionPostPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSAuctionPostPacket.cs index 0dd1458c10..4b456a54c1 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSAuctionPostPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSAuctionPostPacket.cs @@ -1,6 +1,7 @@ using AAEmu.Commons.Network; using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Network.Game; +using AAEmu.Game.Models.Game.Auction; namespace AAEmu.Game.Core.Packets.C2G; @@ -12,13 +13,17 @@ public CSAuctionPostPacket() : base(CSOffsets.CSAuctionPostPacket, 5) public override void Read(PacketStream stream) { - var npcObjId = stream.ReadBc(); - var npcObjId2 = stream.ReadBc(); + var auctioneerId = stream.ReadBc(); + var auctioneerId2 = stream.ReadBc(); var itemId = stream.ReadUInt64(); var startPrice = stream.ReadInt32(); var buyoutPrice = stream.ReadInt32(); - var duration = stream.ReadByte(); + var duration = (AuctionDuration)stream.ReadByte(); + var minStack = stream.ReadInt32(); + var maxStack = stream.ReadInt32(); - AuctionManager.Instance.ListAuctionItem(Connection.ActiveChar, itemId, startPrice, buyoutPrice, duration); + Logger.Warn($"AuctionMyBidList, auctioneerId: {auctioneerId}, auctioneerId2: {auctioneerId2}, itemId: {itemId}, startPrice: {startPrice}, buyoutPrice: {buyoutPrice}, duration: {duration}, minStack: {minStack}, maxStack: {maxStack}"); + + AuctionManager.Instance.PostLotOnAuction(Connection.ActiveChar, auctioneerId, auctioneerId2, itemId, startPrice, buyoutPrice, duration, minStack, maxStack); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSAuctionSearchPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSAuctionSearchPacket.cs index e5d2da5dae..3fdeb0b1e5 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSAuctionSearchPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSAuctionSearchPacket.cs @@ -1,8 +1,7 @@ using AAEmu.Commons.Network; using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Network.Game; -using AAEmu.Game.Core.Packets.G2C; -using AAEmu.Game.Models.Game.Auction.Templates; +using AAEmu.Game.Models.Game.Auction; namespace AAEmu.Game.Core.Packets.C2G; @@ -15,26 +14,14 @@ public CSAuctionSearchPacket() : base(CSOffsets.CSAuctionSearchPacket, 5) public override void Read(PacketStream stream) { - var _sTemplate = new AuctionSearchTemplate(); - var objId = stream.ReadBytes(6); - _sTemplate.Player = Connection.ActiveChar; - _sTemplate.ItemName = stream.ReadString(); - _sTemplate.ExactMatch = stream.ReadBoolean(); - _sTemplate.Grade = stream.ReadByte(); - _sTemplate.CategoryA = stream.ReadByte(); - _sTemplate.CategoryB = stream.ReadByte(); - _sTemplate.CategoryC = stream.ReadByte(); - _sTemplate.Page = stream.ReadUInt32(); - _sTemplate.PlayerId = stream.ReadUInt32(); - _sTemplate.Filter = stream.ReadUInt32(); - _sTemplate.WorldID = stream.ReadByte(); - _sTemplate.MinItemLevel = stream.ReadByte(); - _sTemplate.MaxItemLevel = stream.ReadByte(); - _sTemplate.SortKind = stream.ReadByte(); - _sTemplate.SortOrder = stream.ReadByte(); + var auctioneerId = stream.ReadBc(); + var auctioneerId2 = stream.ReadBc(); - var foundItems = AuctionManager.Instance.GetAuctionItems(_sTemplate); + var auctionSearch = new AuctionSearch(); + auctionSearch.Read(stream); - Connection.SendPacket(new SCAuctionSearchedPacket(foundItems, _sTemplate.Page)); + Logger.Warn($"AuctionSearch, auctioneerId: {auctioneerId}, auctioneerId: {auctioneerId2}, Keyword: {auctionSearch.Keyword}"); + + AuctionManager.Instance.SearchAuctionLots(Connection.ActiveChar, auctionSearch); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSAuctionSearchSoldRecordPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSAuctionSearchSoldRecordPacket.cs index 5fa7ccc389..56a30f3d2c 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSAuctionSearchSoldRecordPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSAuctionSearchSoldRecordPacket.cs @@ -9,16 +9,15 @@ public class CSAuctionSearchSoldRecordPacket : GamePacket { public CSAuctionSearchSoldRecordPacket() : base(CSOffsets.CSAuctionSearchSoldRecordPacket, 5) { - } + } public override void Read(PacketStream stream) { - var itemTemplateId = stream.ReadUInt32(); - var itemGrade = stream.ReadByte(); + var itemTemplateId = stream.ReadUInt32(); + var itemGrade = stream.ReadByte(); - var cheapestItem = AuctionManager.Instance.GetCheapestAuctionItem(itemTemplateId); + var solds = AuctionManager.Instance.GetSalesForLast14Days(itemTemplateId, itemGrade); - Connection.ActiveChar.SendPacket(new SCAuctionSoldRecordPacket(cheapestItem)); - - } -} \ No newline at end of file + Connection.ActiveChar.SendPacket(new SCAuctionSoldRecordPacket(itemTemplateId, itemGrade, solds)); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSBidAuctionPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSBidAuctionPacket.cs deleted file mode 100644 index f430a4726e..0000000000 --- a/AAEmu.Game/Core/Packets/C2G/CSBidAuctionPacket.cs +++ /dev/null @@ -1,53 +0,0 @@ -//using AAEmu.Commons.Network; -//using AAEmu.Game.Core.Managers; -//using AAEmu.Game.Core.Network.Game; - -//namespace AAEmu.Game.Core.Packets.C2G; - -//public class CSBidAuctionPacket : GamePacket -//{ -// public CSBidAuctionPacket() : base(CSOffsets.CSBidAuctionPacket, 5) -// { -// } - -// public override void Read(PacketStream stream) -// { -// var npcObjId = stream.ReadBc(); -// var npcObjId2 = stream.ReadBc(); - -// var auctionId = stream.ReadUInt64(); -// var duration = stream.ReadByte(); -// var itemId = stream.ReadUInt32(); -// var objectId = stream.ReadUInt64(); -// var grade = stream.ReadByte(); -// var bound = stream.ReadByte(); -// var stackSize = stream.ReadUInt32(); -// var detailType = stream.ReadByte(); -// var creationTime = stream.ReadDateTime(); -// var lifeSpan = stream.ReadUInt32(); -// var type1 = stream.ReadUInt32(); -// var worldID = stream.ReadByte(); -// var unsecureTime = stream.ReadDateTime(); -// var unpackTime = stream.ReadDateTime(); -// var worldId2 = stream.ReadByte(); -// var type2 = stream.ReadUInt32(); -// var clientName = stream.ReadString(); -// var startMoney = stream.ReadUInt32(); -// var directMoney = stream.ReadUInt32(); -// var timeLeft = stream.ReadUInt64(); -// var bidWorld = stream.ReadByte(); -// var type3 = stream.ReadUInt32(); -// var bidderName = stream.ReadString(); -// var bidMoney = stream.ReadUInt32(); -// var extra = stream.ReadUInt32(); - -// var typeBid = stream.ReadUInt64(); -// var biddingWorldID = stream.ReadByte(); -// var typeBid2 = stream.ReadUInt32(); -// var name = stream.ReadString(); -// var bid = stream.ReadInt32(); - - -// AuctionManager.Instance.BidOnAuctionItem(Connection.ActiveChar, auctionId, bid); -// } -//} diff --git a/AAEmu.Game/Core/Packets/C2G/CSBroadcastVisualOption_0_Packet.cs b/AAEmu.Game/Core/Packets/C2G/CSBroadcastVisualOption_0_Packet.cs index c12f99092a..8c4dce7e2d 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSBroadcastVisualOption_0_Packet.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSBroadcastVisualOption_0_Packet.cs @@ -1,9 +1,14 @@ -using AAEmu.Commons.Network; +using System; + +using AAEmu.Commons.Network; using AAEmu.Game.Core.Managers; +using AAEmu.Game.Core.Managers.UnitManagers; using AAEmu.Game.Core.Network.Connections; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Char; +using AAEmu.Game.Models.Game.Items.Actions; +using AAEmu.Game.Models.Game.Skills; using AAEmu.Game.Models.Observers; namespace AAEmu.Game.Core.Packets.C2G; @@ -22,16 +27,35 @@ public override void Read(PacketStream stream) Connection.ActiveChar.VisualOptions = new CharacterVisualOptions(); Connection.ActiveChar.VisualOptions.Read(stream); + Connection.ActiveChar.Buffs.AddBuff((uint)BuffConstants.LoggedOn, Connection.ActiveChar); + var template = CharacterManager.Instance.GetTemplate(character.Race, character.Gender); + foreach (var buff in template.Buffs) + { + var buffTemplate = SkillManager.Instance.GetBuffTemplate(buff); + var casterObj = new SkillCasterUnit(character.ObjId); + character.Buffs.AddBuff(new Buff(character, character, casterObj, buffTemplate, null, DateTime.UtcNow) { Passive = true }); + } + character.Breath = character.LungCapacity; + // TODO: Fix the patron and auction house license buff issue + Connection.ActiveChar.Buffs.AddBuff((uint)SkillConstants.PatronStatus, Connection.ActiveChar); + //Connection.ActiveChar.Buffs.AddBuff((uint)SkillConstants.PatronPlus, Connection.ActiveChar); + //Connection.ActiveChar.Buffs.AddBuff((uint)SkillConstants.Patron, Connection.ActiveChar); + //Connection.ActiveChar.Buffs.AddBuff((uint)SkillConstants.AuctionLicense, Connection.ActiveChar); + Connection.SendPacket(new SCUnitStatePacket(Connection.ActiveChar)); Connection.ActiveChar.PushSubscriber(TimeManager.Instance.Subscribe(Connection, new TimeOfDayObserver(Connection.ActiveChar))); - //Connection.SendPacket(new SCCooldownsPacket(Connection.ActiveChar)); - //Connection.SendPacket(new SCListSkillActiveTypsPacket([])); - //Connection.SendPacket(new SCDetailedTimeOfDayPacket(12f)); - //Connection.SendPacket(new SCActionSlotsPacket(Connection.ActiveChar.Slots)); + Connection.SendPacket(new SCCooldownsPacket(Connection.ActiveChar)); + Connection.SendPacket(new SCListSkillActiveTypsPacket([])); + Connection.SendPacket(new SCDetailedTimeOfDayPacket(12f)); + Connection.SendPacket(new SCActionSlotsPacket(Connection.ActiveChar.Slots)); + + Connection.ActiveChar.BroadcastPacket(new SCReputationChangedPacket(DateTime.UtcNow, false), true); + //Connection.ActiveChar.BroadcastPacket(new SCItemTaskSuccessPacket(ItemTaskType.ItemTaskRemoveHeroReward, [], []), true); - Logger.Info("CSBroadcastVisualOption_0"); Connection.ActiveChar.BroadcastPacket(new SCUnitVisualOptionsPacket(Connection.ActiveChar.ObjId, Connection.ActiveChar.VisualOptions), true); + + Logger.Info("CSBroadcastVisualOption_0"); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSBuyItemsPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSBuyItemsPacket.cs index d49e606273..b6218da289 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSBuyItemsPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSBuyItemsPacket.cs @@ -6,7 +6,6 @@ using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Core.Packets.G2C; -using AAEmu.Game.Models.Game; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; using AAEmu.Game.Models.Game.Merchant; @@ -26,6 +25,7 @@ public override void Read(PacketStream stream) List pack = null; var npcObjId = stream.ReadBc(); + var npc = WorldManager.Instance.GetNpc(npcObjId); // If a NPC was provided, check if it's valid if (npc != null) @@ -44,11 +44,16 @@ public override void Read(PacketStream stream) } var doodadObjId = stream.ReadBc(); + var doodad = WorldManager.Instance.GetDoodad(doodadObjId); // If a Doodad was provided, check if we're near it if (doodadObjId != 0) { - if (doodad == null) return; + if (doodad == null) + { + return; + } + var dist = MathUtil.CalculateDistance(Connection.ActiveChar.Transform.World.Position, doodad.Transform.World.Position); if (dist > 3f) // 3m should be enough for these { @@ -78,7 +83,9 @@ public override void Read(PacketStream stream) // If using a NPC shop, check if the NPC is selling the specified item if (npcObjId != 0 && (pack == null || !Merchants.SellsItem(itemId, pack))) + { continue; + } if (doodadObjId != 0) { @@ -90,13 +97,21 @@ public override void Read(PacketStream stream) var template = ItemManager.Instance.GetTemplate(itemId); if (currency == ShopCurrencyType.Money) + { money += template.Price * count; + } else if (currency == ShopCurrencyType.Honor) + { honorPoints += template.HonorPrice * count; + } else if (currency == ShopCurrencyType.VocationBadges) + { vocationBadges += template.LivingPointPrice * count; + } else + { Logger.Error("Unknown currency type"); + } } // Get a list of items to buy from the buyback window @@ -106,7 +121,10 @@ public override void Read(PacketStream stream) var index = stream.ReadInt32(); var item = Connection.ActiveChar.BuyBackItems.GetItemBySlot(index); if (item == null) + { continue; + } + itemsBuyBack.Add(item, index); money += (int)(item.Template.Refund * ItemManager.Instance.GetGradeTemplate(item.Grade).RefundMultiplier / 100f) * item.Count; } @@ -115,7 +133,9 @@ public override void Read(PacketStream stream) var openType = stream.ReadByte(); if (money > Connection.ActiveChar.Money && honorPoints > Connection.ActiveChar.HonorPoint && vocationBadges > Connection.ActiveChar.VocationPoint) + { return; + } var tasks = new List(); foreach (var (itemId, grade, count) in itemsBuy) @@ -132,13 +152,20 @@ public override void Read(PacketStream stream) } if (honorPoints > 0) + { Connection.ActiveChar.ChangeGamePoints(GamePointKind.Honor, -honorPoints); + } if (vocationBadges > 0) + { Connection.ActiveChar.ChangeGamePoints(GamePointKind.Vocation, -vocationBadges); + } if (money > 0) - Connection.ActiveChar.ChangeMoney(SlotType.Inventory, -money); + { + //Connection.ActiveChar.ChangeMoney(SlotType.Bag, -money); + tasks.Add(new MoneyChange(money)); + } Connection.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.StoreBuy, tasks, new List())); } diff --git a/AAEmu.Game/Core/Packets/C2G/CSCancelAuctionPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSCancelAuctionPacket.cs deleted file mode 100644 index 59d11fd66b..0000000000 --- a/AAEmu.Game/Core/Packets/C2G/CSCancelAuctionPacket.cs +++ /dev/null @@ -1,47 +0,0 @@ -//using AAEmu.Commons.Network; -//using AAEmu.Game.Core.Managers; -//using AAEmu.Game.Core.Network.Game; - -//namespace AAEmu.Game.Core.Packets.C2G; - -//public class CSCancelAuctionPacket : GamePacket -//{ -// public CSCancelAuctionPacket() : base(CSOffsets.CSCancelAuctionPacket, 5) -// { -// } - -// public override void Read(PacketStream stream) -// { -// var npcObjId = stream.ReadBc(); -// var npcObjId2 = stream.ReadBc(); - -// var auctionId = stream.ReadUInt64(); -// var duration = stream.ReadByte(); -// var itemId = stream.ReadUInt32(); -// var objectId = stream.ReadUInt64(); -// var grade = stream.ReadByte(); -// var bound = stream.ReadByte(); -// var stackSize = stream.ReadUInt32(); -// var detailType = stream.ReadByte(); -// var creationTime = stream.ReadDateTime(); -// var lifeSpan = stream.ReadUInt32(); -// var type1 = stream.ReadUInt32(); -// var worldID = stream.ReadByte(); -// var unsecureTime = stream.ReadDateTime(); -// var unpackTime = stream.ReadDateTime(); -// var worldId2 = stream.ReadByte(); -// var type2 = stream.ReadUInt32(); -// var clientName = stream.ReadString(); -// var startMoney = stream.ReadUInt32(); -// var directMoney = stream.ReadUInt32(); -// var timeLeft = stream.ReadUInt64(); -// var bidWorld = stream.ReadByte(); -// var type3 = stream.ReadUInt32(); -// var bidderName = stream.ReadString(); -// var bidMoney = stream.ReadUInt32(); -// var extra = stream.ReadUInt32(); -// var player = Connection.ActiveChar; - -// AuctionManager.Instance.CancelAuctionItem(player, auctionId); -// } -//} diff --git a/AAEmu.Game/Core/Packets/C2G/CSChangeAutoUseAaPointPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSChangeAutoUseAaPointPacket.cs new file mode 100644 index 0000000000..25899d9b2f --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSChangeAutoUseAaPointPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSChangeAutoUseAaPointPacket : GamePacket +{ + public CSChangeAutoUseAaPointPacket() : base(CSOffsets.CSChangeAutoUseAaPointPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSChangeAutoUseAaPointPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSChangeClientNpcTargetPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSChangeClientNpcTargetPacket.cs new file mode 100644 index 0000000000..5a60e82f7c --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSChangeClientNpcTargetPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSChangeClientNpcTargetPacket : GamePacket +{ + public CSChangeClientNpcTargetPacket() : base(CSOffsets.CSChangeClientNpcTargetPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSChangeClientNpcTargetPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSChangeMateEquipmentPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSChangeMateEquipmentPacket.cs index 4bde5ca3ad..17b6d6325e 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSChangeMateEquipmentPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSChangeMateEquipmentPacket.cs @@ -59,7 +59,7 @@ public override void Read(PacketStream stream) mateItem.SlotNumber = stream.ReadByte(); var expireTime = stream.ReadDateTime(); // add in 5+ - + var isEquip = playerItem.Item.TemplateId != 0; // Override the Read data with the actual Item data diff --git a/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveEquipmentPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveEquipmentPacket.cs index dc66f2ffcf..53afc9ff4a 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveEquipmentPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveEquipmentPacket.cs @@ -1,9 +1,16 @@ -using AAEmu.Commons.Network; +using System; +using System.Collections.Generic; + +using AAEmu.Commons.Network; using AAEmu.Game.Core.Managers; +using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Core.Packets.G2C; +using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; +using AAEmu.Game.Models.Game.Slaves; +using AAEmu.Game.Models.Game.Units; namespace AAEmu.Game.Core.Packets.C2G { @@ -46,10 +53,10 @@ public override void Read(PacketStream stream) var slaveItem = new ItemAndLocation(); playerItem.Item = new Item(); - playerItem.Item.Read(stream); + stream.Read(playerItem.Item); slaveItem.Item = new Item(); - slaveItem.Item.Read(stream); + stream.Read(slaveItem.Item); playerItem.SlotType = (SlotType)stream.ReadByte(); playerItem.SlotNumber = stream.ReadByte(); @@ -86,17 +93,114 @@ public override void Read(PacketStream stream) 0, slaveItem.SlotType, slaveItem.SlotNumber); // character.SendMessage($"SCMateEquipmentChanged - {(isEquip ? playerItem : mateItem)} -> {(isEquip ? mateItem : playerItem)}, MateTl: {mateTl} => Success {res}"); - if (!res) + //if (!res) { - character.SendPacket(new SCMateEquipmentChangedPacket( + character.SendPacket(new SCSlaveEquipmentChangedPacket( isEquip ? playerItem : slaveItem, isEquip ? slaveItem : playerItem, slaveTl, owningPlayerId, dbSlaveId, bts, res, expireTime)); } + + // TODO добавить удаление Slaves + if (!isEquip) + { + var slaveId = ItemManager.Instance.GetSlaveIdByItemId(playerItem.Item.TemplateId); + if (slaveId > 0) + { + DespawnSlave(slave, slaveId); + } + else + { + var doodadId = ItemManager.Instance.GetDoodadIdByItemId(playerItem.Item.TemplateId); + if (doodadId > 0) + { + DespawnDoodad(slave, doodadId); + } + } + } + else + { + var slaveId = ItemManager.Instance.GetSlaveIdByItemId(playerItem.Item.TemplateId); + if (slaveId > 0) + { + SpawnSlave(character, slave, playerItem, slaveId); + } + else + { + var doodadId = ItemManager.Instance.GetDoodadIdByItemId(playerItem.Item.TemplateId); + if (doodadId <= 0) { continue; } + + SpawnDoodad(character, slave, playerItem, doodadId); + } + } } } } + + private static void DespawnDoodad(Slave slave, uint doodadId) + { + var doodad = slave.GetDoodadByItemTemplateId(doodadId); + //doodad?.DoDespawn(doodad); + doodad.IsPersistent = false; + doodad.Despawn = DateTime.UtcNow; + SpawnManager.Instance.AddDespawn(doodad); + slave.AttachedDoodads.Remove(doodad); + } + + private static void DespawnSlave(Slave slave, uint slaveId) + { + var attachedSlave = slave.GetSlaveByItemTemplateId(slaveId); + WorldManager.Instance.RemoveObject(attachedSlave); + attachedSlave.Despawn = DateTime.UtcNow; + SpawnManager.Instance.AddDespawn(attachedSlave); + slave.AttachedSlaves.Remove(attachedSlave); + } + + private static void SpawnSlave(Character character, Slave slave, ItemAndLocation playerItem, uint slaveId) + { + var attachPoint = SlaveManager.Instance.GetAttachPointBySlotId(slave.TemplateId, (uint)playerItem.Item.Slot); + var byteArray = new byte[12]; + Buffer.BlockCopy(BitConverter.GetBytes(slave.Hp), 0, byteArray, 0, 4); + Buffer.BlockCopy(BitConverter.GetBytes(0ul), 0, byteArray, 4, 8); + playerItem.Item.Detail = byteArray; + playerItem.Item.DetailType = ItemDetailType.SlaveEquipment; + playerItem.Item.DetailBytesLength = 12; + playerItem.Item.ItemFlags = ItemFlag.SoulBound; // связанный + playerItem.Item.ChargeUseSkillTime = DateTime.UtcNow; + + character.SendPacket(new SCUpdateSlaveSourceItemPacket(slave.ObjId, playerItem.Item.Id, slave.Hp, (byte)playerItem.Item.Slot)); + var slaveBinding = new SlaveBindings + { + Id = 0, + OwnerId = slave.TemplateId, + OwnerType = "Slave", + SlaveId = slaveId, + AttachPointId = attachPoint + }; + SlaveManager.Instance.SpawnSlaveSlaves(character, slaveBinding, slave); + } + + private static void SpawnDoodad(Character character, Slave slave, ItemAndLocation playerItem, uint doodadId) + { + // Send Item manipulation packet + character.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.DoodadCreate, [], [], 20)); + + var attachPoint2 = SlaveManager.Instance.GetAttachPointBySlotId(slave.TemplateId, (uint)playerItem.Item.Slot); + var doodadBinding = new SlaveDoodadBindings + { + Id = 0, + OwnerId = slave.TemplateId, + OwnerType = "Slave", + DoodadId = doodadId, + Persist = true, // будем ли сохранять в базе + Scale = 1f, + AttachPointId = attachPoint2 + }; + + // Create all the trinkets that have been downloaded from inventory. + SlaveManager.Instance.CreateSlaveDoodads(character, playerItem.Item, slave, doodadBinding); + } } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveNamePacket.cs b/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveNamePacket.cs index 98d0ca41d9..7280d13c94 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveNamePacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveNamePacket.cs @@ -1,4 +1,5 @@ using AAEmu.Commons.Network; +using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Network.Game; namespace AAEmu.Game.Core.Packets.C2G; @@ -15,5 +16,8 @@ public override void Read(PacketStream stream) var name = stream.ReadString(); Logger.Debug("ChangeSlaveName, Tl: {0}, Name: {1}", tl, name); + + SlaveManager.Instance.RenameSlave(Connection, tl, name); + } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSCompletedTutorialPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSCompletedTutorialPacket.cs index 04dbc4e129..2b92cf97fc 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSCompletedTutorialPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSCompletedTutorialPacket.cs @@ -1,6 +1,7 @@ using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Core.Packets.G2C; +using AAEmu.Game.Models.Game.Items.Actions; namespace AAEmu.Game.Core.Packets.C2G; @@ -21,5 +22,6 @@ public override void Read(PacketStream stream) completedQuestBlock.Body.CopyTo(body, 0); Connection.SendPacket(new SCTutorialCompletedPacket(id, body)); + Connection.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.QuestComplete, [], [])); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSDemoCharResetPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSDemoCharResetPacket.cs new file mode 100644 index 0000000000..72431e8f81 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSDemoCharResetPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSDemoCharResetPacket : GamePacket +{ + public CSDemoCharResetPacket() : base(CSOffsets.CSDemoCharResetPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSDemoCharResetPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSDepositMoneyPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSDepositMoneyPacket.cs index 01bab7af19..ddd781f600 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSDepositMoneyPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSDepositMoneyPacket.cs @@ -17,6 +17,6 @@ public override void Read(PacketStream stream) Logger.Debug("DepositMoney: amount -> {0}, aa_point -> {1}", amount, aapoint); - Connection.ActiveChar.ChangeMoney(SlotType.Inventory, SlotType.Bank, amount); + Connection.ActiveChar.ChangeMoney(SlotType.Bag, SlotType.Bank, amount); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSHeroAbstainPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSHeroAbstainPacket.cs new file mode 100644 index 0000000000..f0c150f634 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSHeroAbstainPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSHeroAbstainPacket : GamePacket +{ + public CSHeroAbstainPacket() : base(CSOffsets.CSHeroAbstainPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSHeroAbstainPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSHeroCandidateListPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSHeroCandidateListPacket.cs new file mode 100644 index 0000000000..0da8ab29ba --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSHeroCandidateListPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSHeroCandidateListPacket : GamePacket +{ + public CSHeroCandidateListPacket() : base(CSOffsets.CSHeroCandidateListPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSHeroCandidateListPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSHeroRankingListPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSHeroRankingListPacket.cs new file mode 100644 index 0000000000..9099e31efe --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSHeroRankingListPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSHeroRankingListPacket : GamePacket +{ + public CSHeroRankingListPacket() : base(CSOffsets.CSHeroRankingListPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSHeroRankingListPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSHeroVotingPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSHeroVotingPacket.cs new file mode 100644 index 0000000000..d266022ef8 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSHeroVotingPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSHeroVotingPacket : GamePacket +{ + public CSHeroVotingPacket() : base(CSOffsets.CSHeroVotingPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSHeroVotingPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSInteractGimmickPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSInteractGimmickPacket.cs new file mode 100644 index 0000000000..08ec7a785c --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSInteractGimmickPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSInteractGimmickPacket : GamePacket +{ + public CSInteractGimmickPacket() : base(CSOffsets.CSInteractGimmickPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSInteractGimmickPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSJurySentencePacket.cs b/AAEmu.Game/Core/Packets/C2G/CSJurySentencePacket.cs new file mode 100644 index 0000000000..c5dca08324 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSJurySentencePacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSJurySentencePacket : GamePacket +{ + public CSJurySentencePacket() : base(CSOffsets.CSJurySentencePacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSJurySentencePacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSListMailContinuePacket.cs b/AAEmu.Game/Core/Packets/C2G/CSListMailContinuePacket.cs index 629d37fec7..bcacba30fa 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSListMailContinuePacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSListMailContinuePacket.cs @@ -14,5 +14,7 @@ public override void Read(PacketStream stream) var mailBoxListKind = stream.ReadByte(); Logger.Debug($"ListMailContinue: mailBoxListKind {mailBoxListKind}"); + + Connection.ActiveChar.Mails.SendMailListContinue(mailBoxListKind); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSListMailPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSListMailPacket.cs index e4e8541adc..bb3ff91962 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSListMailPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSListMailPacket.cs @@ -19,6 +19,6 @@ public override void Read(PacketStream stream) Logger.Debug($"CSListMailPacket: mailBoxListKind={mailBoxListKind}, startIdx={startIdx}, sentCnt={sentCnt}, isRecover={isRecover}, isTest={isTest}"); - Connection.ActiveChar.Mails.OpenMailbox(mailBoxListKind); + Connection.ActiveChar.Mails.SendMailList(mailBoxListKind, startIdx, sentCnt, isRecover, isTest); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSListSoldItemPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSListSoldItemPacket.cs index bda24c821f..b7d93b4264 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSListSoldItemPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSListSoldItemPacket.cs @@ -14,6 +14,8 @@ public CSListSoldItemPacket() : base(CSOffsets.CSListSoldItemPacket, 5) public override void Read(PacketStream stream) { var npcObjId = stream.ReadBc(); + var doodadObjId = stream.ReadBc(); + var npc = WorldManager.Instance.GetNpc(npcObjId); if (npc == null || !npc.Template.Merchant) return; diff --git a/AAEmu.Game/Core/Packets/C2G/CSNotifyInGameCompletedPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSNotifyInGameCompletedPacket.cs index ce1e50d9c0..99c9cbb169 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSNotifyInGameCompletedPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSNotifyInGameCompletedPacket.cs @@ -15,11 +15,12 @@ public CSNotifyInGameCompletedPacket() : base(CSOffsets.CSNotifyInGameCompletedP public override void Read(PacketStream stream) { - //Connection.SendPacket(new SCScheduledEventStartedPacket()); + Connection.SendPacket(new SCScheduledEventStartedPacket()); Connection.SendPacket(new SCGlobalGameStatusAckPacket()); Connection.SendPacket(new SCSpawnedMonitorNpcsPacket()); Connection.SendPacket(new SCChatMessagePacket(ChatType.System, AppConfiguration.Instance.World.MOTD)); // "Welcome to AAEmu!" + Connection.SendPacket(new SCDelayedTaskOnInGameNotifyPacket()); WorldManager.Instance.OnPlayerJoin(Connection.ActiveChar); Logger.Info("NotifyInGameCompleted SubZoneId {0}", Connection.ActiveChar.SubZoneId); diff --git a/AAEmu.Game/Core/Packets/C2G/CSNotifyInGamePacket.cs b/AAEmu.Game/Core/Packets/C2G/CSNotifyInGamePacket.cs index 8dc892d1dc..8b84176d86 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSNotifyInGamePacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSNotifyInGamePacket.cs @@ -1,8 +1,10 @@ -using AAEmu.Commons.Network; +using System; + +using AAEmu.Commons.Network; using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Core.Packets.G2C; -using AAEmu.Game.Models; +using AAEmu.Game.Models.Game.Char.Static; using AAEmu.Game.Models.Game.Chat; namespace AAEmu.Game.Core.Packets.C2G; @@ -26,7 +28,7 @@ public override void Execute() ResidentManager.Instance.UpdateAtLogin(Connection.ActiveChar); - Connection.SendPacket(new SCScheduledEventStartedPacket()); + //Connection.SendPacket(new SCScheduledEventStartedPacket()); // Joining channel 1 (shout) will automatically also join /lfg and /trade for that zone on the client-side // Back in 1.x /trade was zone base, not faction based @@ -39,15 +41,20 @@ public override void Execute() //TeamManager.Instance.UpdateAtLogin(Connection.ActiveChar); //Connection.ActiveChar.Expedition?.OnCharacterLogin(Connection.ActiveChar); //ExpeditionManager.SendMyExpeditionDescInfo(Connection.ActiveChar); - - //if (Connection.ActiveChar.Attendances.Attendances?.Count == 0) - //{ - // Connection.ActiveChar.Attendances.SendEmptyAttendances(); - //} - //else - //{ - // Connection.ActiveChar.Attendances.Send(); - //} + + Connection.ActiveChar.SendPacket(new SCDailyCountPacket(0, 0, 5)); + Connection.ActiveChar.SendPacket(new SCDailyResetPacket(DailyResetKind.Instance)); + Connection.ActiveChar.SendPacket(new SCDailyResetPacket(DailyResetKind.AbilitySetFreeActivationCount)); + Connection.ActiveChar.SendPacket(new SCCurServerTimePacket(DateTime.UtcNow)); + + if (Connection.ActiveChar.Attendances.Attendances?.Count == 0) + { + Connection.ActiveChar.Attendances.SendEmptyAttendances(); + } + else + { + Connection.ActiveChar.Attendances.Send(); + } Connection.ActiveChar.UpdateGearBonuses(null, null); diff --git a/AAEmu.Game/Core/Packets/C2G/CSOffsets.cs b/AAEmu.Game/Core/Packets/C2G/CSOffsets.cs index 31dcacd70c..6e33186337 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSOffsets.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSOffsets.cs @@ -6,7 +6,7 @@ public static class CSOffsets public const ushort X2EnterWorldPacket = 0x000; // double _01_&_05_ public const ushort CSResturnAddrsPacket = 0x074; // level = 1 - public const ushort CSResturnAddrs_05_Packet = 0xfff; // level = 5 + public const ushort CSResturnAddrs_05_Packet = 0x074; // level = 5 public const ushort CSHgResponsePacket = 0x13E; // level = 1+ public const ushort CSHgResponse_05_Packet = 0x13E; // level = 5+ public const ushort CSAesXorKeyPacket = 0x1A2; // level = 1+ @@ -55,7 +55,7 @@ public static class CSOffsets public const ushort CSRequestGameEventInfoPacket = 0x05B; public const ushort off_39E822E0 = 0x18A; public const ushort off_39E822F0 = 0x168; - public const ushort CSChangeMateNamePacket = 0xfff; + public const ushort CSChangeMateNamePacket = 0x03E; public const ushort CSSendNationMemberCountListPacket = 0x09F; public const ushort CSNationSendExpeditionImmigrationAcceptRejectPacket = 0x1E6; public const ushort CSSendExpeditionImmigrationListPacket = 0x0F8; @@ -95,7 +95,7 @@ public static class CSOffsets public const ushort CSJuryEndTestimonyPacket = 0x12F; public const ushort CSCancelTrialPacket = 0x0ED; public const ushort CSJurySentencePacket = 0x0D3; - public const ushort CSReportCrimePacket = 0xfff; + public const ushort CSReportCrimePacket = 0x1BE; public const ushort CSRequestJuryWaitingNumberPacket = 0x1CC; public const ushort CSRequestSetBountyPacket = 0x1B8; public const ushort CSUpdateBountyPacket = 0x15C; @@ -116,7 +116,7 @@ public static class CSOffsets public const ushort CSIdleStatusPacket = 0x1A9; public const ushort CSChangeClientNpcTargetPacket = 0x10D; public const ushort CSCompletedCinemaPacket = 0x0E6; - public const ushort off_39E97AFC = 0x122; + public const ushort CSCheckDemoModePacket = 0x122; // off_39E97AFC public const ushort CSDemoCharResetPacket = 0x174; public const ushort CSConsoleCmdUsedPacket = 0x07A; public const ushort CSEditorGameModePacket = 0x0E5; @@ -164,7 +164,7 @@ public static class CSOffsets public const ushort CSEnprotectStubCallResponsePacket = 0x0B4; public const ushort CSRepresentCharacterPacket = 0x187; public const ushort off_39E9A31C = 0x087; - public const ushort CSCheckDemoModePacket = 0x114; + public const ushort CSStoppedCinemaPacket = 0x114; // off_39E9A32C public const ushort CSCreateCharacterPacket = 0x0F2; public const ushort CSEditCharacterPacket = 0x064; public const ushort CSBroadcastVisualOption_0_Packet = 0x126; //0x126; @@ -234,8 +234,8 @@ public static class CSOffsets public const ushort CSSetTeamMemberRolePacket = 0x1B0; public const ushort CSSetOverHeadMarkerPacket = 0x12E; public const ushort CSAskRiskyTeamActionPacket = 0x0D5; - public const ushort CSTeamAcceptHandOverOwnerPacket = 0xFFF; - public const ushort CSTeamAcceptOwnerOfferPacket = 0xFFF; + public const ushort CSTeamAcceptHandOverOwnerPacket = 0x009; + public const ushort CSTeamAcceptOwnerOfferPacket = 0x09C; public const ushort off_39EBBCE8 = 0x191; public const ushort off_39EBBCF8 = 0x0F5; public const ushort off_39EBBD08 = 0x0E0; @@ -253,10 +253,10 @@ public static class CSOffsets public const ushort CSCreateHousePacket = 0x062; public const ushort CSLeaveBeautyShopPacket = 0x15B; public const ushort CSConstructHouseTaxPacket = 0x0B1; - public const ushort CSChangeHouseNamePacket = 0xfff; + public const ushort CSChangeHouseNamePacket = 0x081; public const ushort CSChangeHousePermissionPacket = 0x08A; public const ushort CSRequestHouseTaxPacket = 0x177; - public const ushort CSPerpayHouseTaxPacket = 0x17C; + public const ushort CSPrepayHouseTaxPacket = 0x17C; public const ushort CSAllowRecoverPacket = 0x097; public const ushort CSSellHouseCancelPacket = 0x0A7; public const ushort CSDecorateHousePacket = 0x1D0; @@ -316,7 +316,7 @@ public static class CSOffsets public const ushort CSCleanupLogicLinkPacket = 0x1E3; public const ushort CSSelectInteractionExPacket = 0x0A6; public const ushort CSChangeDoodadDataPacket = 0x143; - public const ushort CSBuyItemsPacket = 0x180; + public const ushort off_39EC35CC = 0x180; public const ushort off_39EC35DC = 0x1CB; public const ushort off_39EC35EC = 0x0D7; public const ushort CSUnitAttachedPacket = 0x1AC; //off_39EC3600 @@ -367,10 +367,10 @@ public static class CSOffsets public const ushort off_39ED1948 = 0x11D; public const ushort CSRefreshBotCheckInfoPacket = 0x041; public const ushort CSAnswerBotCheckPacket = 0x1BF; - public const ushort CSChangeSlaveNamePacket = 0xfff; + public const ushort CSChangeSlaveNamePacket = 0x19E; public const ushort off_39ED8054 = 0x163; public const ushort off_39ED8064 = 0x10C; - public const ushort off_39ED8074 = 0x158; + public const ushort CSSearchListPacket = 0x158; // off_39ED8074 public const ushort off_39ED8084 = 0x17B; public const ushort off_39ED8094 = 0x1BC; public const ushort off_39ED80A4 = 0x142; @@ -424,7 +424,7 @@ public static class CSOffsets public const ushort off_39EDCAF0 = 0x1E8; public const ushort CSSellItemsPacket = 0x04A; public const ushort CSListSoldItemPacket = 0x055; - public const ushort off_39EDCB20 = 0x03C; + public const ushort CSBuyItemsPacket = 0x03C; // off_39EDCB20 public const ushort CSSpecialtyCurrentLoadPacket = 0x08F; public const ushort CSStartTradePacket = 0x1D2; public const ushort CSCanStartTradePacket = 0x018; @@ -474,7 +474,7 @@ public static class CSOffsets public const ushort CSRequestSecondPasswordKeyTablesPacket = 0xFFF; public const ushort CSResetQuestContextPacket = 0xFFF; public const ushort CSSaveDoodadUccStringPacket = 0xFFF; - public const ushort CSSearchListPacket = 0xFFF; + //public const ushort CSSearchListPacket = 0xFFF; public const ushort CSSetTeamOfficerPacket = 0xFFF; public const ushort CSSetupSecondPasswordPacket = 0xFFF; public const ushort CSSpecialtyRecordLoadPacket = 0xFFF; diff --git a/AAEmu.Game/Core/Packets/C2G/CSPerpayHouseTaxPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSPrepayHouseTaxPacket.cs similarity index 70% rename from AAEmu.Game/Core/Packets/C2G/CSPerpayHouseTaxPacket.cs rename to AAEmu.Game/Core/Packets/C2G/CSPrepayHouseTaxPacket.cs index 7866dca172..c0bee0ba82 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSPerpayHouseTaxPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSPrepayHouseTaxPacket.cs @@ -3,9 +3,9 @@ namespace AAEmu.Game.Core.Packets.C2G { - public class CSPerpayHouseTaxPacket : GamePacket + public class CSPrepayHouseTaxPacket : GamePacket { - public CSPerpayHouseTaxPacket() : base(CSOffsets.CSPerpayHouseTaxPacket, 5) + public CSPrepayHouseTaxPacket() : base(CSOffsets.CSPrepayHouseTaxPacket, 5) { } @@ -14,7 +14,7 @@ public override void Read(PacketStream stream) var tl = stream.ReadUInt16(); var ausp = stream.ReadBoolean(); - Logger.Debug("CSPerpayHouseTaxPacket, Tl: {0}, ausp: {1}", tl, ausp); + Logger.Debug("CSPrepayHouseTaxPacket, Tl: {0}, ausp: {1}", tl, ausp); //TODO HousingManager.Instance.HouseTaxInfo(Connection, tl, ausp); } diff --git a/AAEmu.Game/Core/Packets/C2G/CSRankSnapshotPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSRankSnapshotPacket.cs new file mode 100644 index 0000000000..f51e3433b4 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSRankSnapshotPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSRankSnapshotPacket : GamePacket +{ + public CSRankSnapshotPacket() : base(CSOffsets.CSRankSnapshotPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSRankSnapshotPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSRemoveAllFieldSlavesPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSRemoveAllFieldSlavesPacket.cs new file mode 100644 index 0000000000..9acf851599 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSRemoveAllFieldSlavesPacket.cs @@ -0,0 +1,22 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Managers; +using AAEmu.Game.Core.Network.Game; +using AAEmu.Game.Models.Game.DoodadObj.Static; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSRemoveAllFieldSlavesPacket : GamePacket +{ + public CSRemoveAllFieldSlavesPacket() : base(CSOffsets.CSRemoveAllFieldSlavesPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + var tlId = stream.ReadUInt16(); // target + + Logger.Debug("CSRemoveAllFieldSlaves, Tl: {0}", tlId); + + SlaveManager.Instance.UnbindSlave(Connection.ActiveChar, tlId, AttachUnitReason.SlaveUnbinding); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSRequestSetBountyPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSRequestSetBountyPacket.cs new file mode 100644 index 0000000000..22625d6d03 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSRequestSetBountyPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSRequestSetBountyPacket : GamePacket +{ + public CSRequestSetBountyPacket() : base(CSOffsets.CSRequestSetBountyPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSRequestSetBountyPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSSearchListPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSSearchListPacket.cs index 476a845f04..94dffe59fd 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSSearchListPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSSearchListPacket.cs @@ -1,5 +1,6 @@ using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; +using AAEmu.Game.Core.Packets.G2C; namespace AAEmu.Game.Core.Packets.C2G; @@ -15,5 +16,8 @@ public override void Read(PacketStream stream) var onlineType = stream.ReadByte(); Logger.Debug("SearchList, ZoneType: {0}, OnlineType: {1}", zoneType, onlineType); + + Connection.SendPacket(new SCSearchListPacket(0, [], false)); + } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSSelectCharacterPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSSelectCharacterPacket.cs index 76fafe235a..686cd24a2f 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSSelectCharacterPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSSelectCharacterPacket.cs @@ -1,15 +1,12 @@ -using System; -using System.Linq; +using System.Linq; using AAEmu.Commons.Network; using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Managers.Id; -using AAEmu.Game.Core.Managers.UnitManagers; using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Char; -using AAEmu.Game.Models.Game.Skills; using AAEmu.Game.Models.Game.Units; using AAEmu.Game.Models.Game.Units.Route; @@ -102,7 +99,7 @@ public override void Read(PacketStream stream) foreach (var house in houses) { - Connection.SendPacket(new SCMyHousePacket(house)); + Connection.SendPacket(new SCHouseStatePacket(house)); } foreach (var conflict in ZoneManager.Instance.GetConflicts()) @@ -119,20 +116,26 @@ public override void Read(PacketStream stream) Connection.ActiveChar.SendOption(5); Connection.ActiveChar.SendOption(6); - Connection.ActiveChar.Buffs.AddBuff((uint)BuffConstants.LoggedOn, Connection.ActiveChar); - var template = CharacterManager.Instance.GetTemplate(character.Race, character.Gender); - foreach (var buff in template.Buffs) - { - var buffTemplate = SkillManager.Instance.GetBuffTemplate(buff); - var casterObj = new SkillCasterUnit(character.ObjId); - character.Buffs.AddBuff(new Buff(character, character, casterObj, buffTemplate, null, DateTime.UtcNow) { Passive = true }); - } - character.Breath = character.LungCapacity; - // TODO: Fix the patron and auction house license buff issue - Connection.ActiveChar.Buffs.AddBuff((uint)SkillConstants.Patron, Connection.ActiveChar); - Connection.ActiveChar.Buffs.AddBuff((uint)SkillConstants.AuctionLicense, Connection.ActiveChar); + //Connection.ActiveChar.Buffs.AddBuff((uint)BuffConstants.LoggedOn, Connection.ActiveChar); + //var template = CharacterManager.Instance.GetTemplate(character.Race, character.Gender); + //foreach (var buff in template.Buffs) + //{ + // var buffTemplate = SkillManager.Instance.GetBuffTemplate(buff); + // var casterObj = new SkillCasterUnit(character.ObjId); + // character.Buffs.AddBuff(new Buff(character, character, casterObj, buffTemplate, null, DateTime.UtcNow) { Passive = true }); + //} + //character.Breath = character.LungCapacity; + //// TODO: Fix the patron and auction house license buff issue + //Connection.ActiveChar.Buffs.AddBuff((uint)SkillConstants.Patron, Connection.ActiveChar); + //Connection.ActiveChar.Buffs.AddBuff((uint)SkillConstants.AuctionLicense, Connection.ActiveChar); Connection.ActiveChar.OnZoneChange(0, Connection.ActiveChar.Transform.ZoneId); + + var scheduleItems = AccountManager.Instance.GetDivineClock(character.AccountId); + if (scheduleItems is not null) + { + character.ScheduleItems = scheduleItems; // updated + } } else { diff --git a/AAEmu.Game/Core/Packets/C2G/CSSellItemsPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSSellItemsPacket.cs index b64ad92609..ca0ceb0db4 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSSellItemsPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSSellItemsPacket.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; + using AAEmu.Commons.Network; using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Network.Game; +using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; @@ -19,9 +21,11 @@ public override void Read(PacketStream stream) var npcObjId = stream.ReadBc(); var npc = WorldManager.Instance.GetNpc(npcObjId); if (npc?.Template.Merchant != true) + { return; + } - var unkObjId = stream.ReadBc(); + var doodadObjId = stream.ReadBc(); var num = stream.ReadByte(); var items = new List(); @@ -40,13 +44,20 @@ public override void Read(PacketStream stream) Item item = null; if (slotType == SlotType.Equipment) + { item = Connection.ActiveChar.Inventory.Equipment.GetItemBySlot(slot); - else if (slotType == SlotType.Inventory) + } + else if (slotType == SlotType.Bag) + { item = Connection.ActiveChar.Inventory.Bag.GetItemBySlot(slot); + } + //else if (slotType == SlotType.Bank) // item = Connection.ActiveChar.Inventory.Bank[slot]; if (item?.Id == itemId) + { items.Add(item); + } } //var tasks = new List(); @@ -54,21 +65,26 @@ public override void Read(PacketStream stream) foreach (var item in items) { if (!item.Template.Sellable) + { continue; + } if (!Connection.ActiveChar.BuyBackItems.AddOrMoveExistingItem(ItemTaskType.StoreSell, item)) { Logger.Warn($"Failed to move sold itemId {item.Id} ({item.TemplateId}) to BuyBack ItemContainer for {Connection.ActiveChar.Name}"); } - money += (int)(item.Template.Refund * ItemManager.Instance.GetGradeTemplate(item.Grade).RefundMultiplier / 100f) * - item.Count; + money += (int)(item.Template.Refund * ItemManager.Instance.GetGradeTemplate(item.Grade).RefundMultiplier / 100f) * item.Count; + } + + if (money == 0) + { + return; } + Connection.ActiveChar.ChangeMoney(SlotType.Bag, money); - Connection.ActiveChar.ChangeMoney(SlotType.Inventory, money); - /* - Connection.ActiveChar.Money += money; - tasks.Add(new MoneyChange(money)); - Connection.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.StoreSell, itemTasks, new List())); - */ + //var itemTasks = new List(); + //Connection.ActiveChar.Money += money; + //itemTasks.Add(new MoneyChange(money)); + //Connection.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.StoreSell, itemTasks, new List())); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSSendExpeditionImmigrationListPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSSendExpeditionImmigrationListPacket.cs new file mode 100644 index 0000000000..87991dc63f --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSSendExpeditionImmigrationListPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSSendExpeditionImmigrationListPacket : GamePacket +{ + public CSSendExpeditionImmigrationListPacket() : base(CSOffsets.CSSendExpeditionImmigrationListPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSSendExpeditionImmigrationListPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSSendMailPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSSendMailPacket.cs index 19031ad6a2..1217674cc4 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSSendMailPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSSendMailPacket.cs @@ -8,6 +8,7 @@ using AAEmu.Game.Models.Game; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; using AAEmu.Game.Utils; namespace AAEmu.Game.Core.Packets.C2G; diff --git a/AAEmu.Game/Core/Packets/C2G/CSSendNationInfoSetPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSSendNationInfoSetPacket.cs new file mode 100644 index 0000000000..1fae887518 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSSendNationInfoSetPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSSendNationInfoSetPacket : GamePacket +{ + public CSSendNationInfoSetPacket() : base(CSOffsets.CSSendNationInfoSetPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSSendNationInfoSetPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSSendNationMemberCountListPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSSendNationMemberCountListPacket.cs new file mode 100644 index 0000000000..5bed52a284 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSSendNationMemberCountListPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSSendNationMemberCountListPacket : GamePacket +{ + public CSSendNationMemberCountListPacket() : base(CSOffsets.CSSendNationMemberCountListPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSSendNationMemberCountListPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSSendRelationFriendPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSSendRelationFriendPacket.cs new file mode 100644 index 0000000000..f3f87948f9 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSSendRelationFriendPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSSendRelationFriendPacket : GamePacket +{ + public CSSendRelationFriendPacket() : base(CSOffsets.CSSendRelationFriendPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSSendRelationFriendPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSSendRelationVotePacket.cs b/AAEmu.Game/Core/Packets/C2G/CSSendRelationVotePacket.cs new file mode 100644 index 0000000000..38d374739d --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSSendRelationVotePacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSSendRelationVotePacket : GamePacket +{ + public CSSendRelationVotePacket() : base(CSOffsets.CSSendRelationVotePacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSSendRelationVotePacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSSkillControllerStatePacket.cs b/AAEmu.Game/Core/Packets/C2G/CSSkillControllerStatePacket.cs index 194054d84b..b46dee52ff 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSSkillControllerStatePacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSSkillControllerStatePacket.cs @@ -22,25 +22,4 @@ public override void Read(PacketStream stream) Logger.Warn("SkillControllerState"); } - - // TODO - /* - * - if ( a2->Reader->field_1C() ) - { - a2->Reader->ReadByte("scType", &v7 + 3, 0); - v2[1] = HIBYTE(v7); - } - else - { - HIBYTE(v7) = *(v2 + 4); - a2->Reader->ReadByte("scType", &v7 + 3, 0); - } - if ( !v2[1] ) - { - a2->Reader->ReadFloat("len", v2 + 2, 0); - a2->Reader->ReadBool("teared", (v2 + 3), 0); - a2->Reader->ReadBool("cutouted", v2 + 13, 0); - } - */ } diff --git a/AAEmu.Game/Core/Packets/C2G/CSStartSkillPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSStartSkillPacket.cs index 9e29e8e83f..998ad7a0b5 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSStartSkillPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSStartSkillPacket.cs @@ -8,6 +8,7 @@ using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Char; +using AAEmu.Game.Models.Game.DoodadObj.Static; using AAEmu.Game.Models.Game.Items.Templates; using AAEmu.Game.Models.Game.Skills; using AAEmu.Game.Models.Game.Skills.Static; @@ -51,7 +52,7 @@ public override void Read(PacketStream stream) skillCastTarget.Read(stream); var flag = stream.ReadByte(); - var flagType = flag & 15; + var flagType = flag & 63; // in 1.2 = 15, in 3+ = 63 var skillObject = SkillObject.GetByType((SkillObjectType)flagType); if (flagType > 0) skillObject.Read(stream); @@ -153,6 +154,16 @@ public override void Read(PacketStream stream) skillResult = skill.Use(Connection.ActiveChar, skillCaster, skillCastTarget, skillObject, false, out skillResultErrorValue); } + // HACKFIX: dismount from slave + if (skillId == (uint)SkillConstants.Dismount) + { + var slave = (Slave)WorldManager.Instance.GetBaseUnit(skillCastTarget.ObjId); + if (slave != null) + { + SlaveManager.Instance.UnbindSlave(Connection.ActiveChar, slave.TlId, AttachUnitReason.SlaveUnbinding); + } + } + if (skillResult != SkillResult.Success) { // It actually sends a skill started packet, but not a skill fired or stopped diff --git a/AAEmu.Game/Core/Packets/C2G/CSStoppedCinemaPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSStoppedCinemaPacket.cs new file mode 100644 index 0000000000..279370c580 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSStoppedCinemaPacket.cs @@ -0,0 +1,17 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSStoppedCinemaPacket : GamePacket +{ + public CSStoppedCinemaPacket() : base(CSOffsets.CSStoppedCinemaPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + // Empty struct + Logger.Warn("CSStoppedCinemaPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSTakeAllAttachmentItemPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSTakeAllAttachmentItemPacket.cs index 934f5829d7..76e8a31dfe 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSTakeAllAttachmentItemPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSTakeAllAttachmentItemPacket.cs @@ -1,7 +1,7 @@ using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Core.Packets.G2C; -using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Core.Packets.C2G; diff --git a/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentSequentially.cs b/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentSequentially.cs deleted file mode 100644 index 7ca3ce9fd5..0000000000 --- a/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentSequentially.cs +++ /dev/null @@ -1,28 +0,0 @@ -//using AAEmu.Commons.Network; -//using AAEmu.Game.Core.Managers; -//using AAEmu.Game.Core.Network.Game; -//using AAEmu.Game.Models.Game; - -//namespace AAEmu.Game.Core.Packets.C2G; - -//public class CSTakeAttachmentSequentially : GamePacket -//{ -// public CSTakeAttachmentSequentially() : base(CSOffsets.CSTakeAttachmentSequentially, 5) -// { -// } - -// public override void Read(PacketStream stream) -// { -// var mailId = stream.ReadInt64(); -// Logger.Debug("TakeAttachmentSequentially, mailId: {0}", mailId); -// var mail = MailManager.Instance.GetMailById(mailId); -// if (mail.Header.ReceiverId != Connection.ActiveChar.Id) // just a check for hackers trying to steal mails -// { -// Connection.ActiveChar.SendErrorMessage(ErrorMessageType.MailInvalid); -// } -// else -// { -// Connection.ActiveChar.Mails.GetAttached(mailId, true, true, true); -// } -// } -//} diff --git a/AAEmu.Game/Core/Packets/C2G/CSTakeScheduleItemPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSTakeScheduleItemPacket.cs new file mode 100644 index 0000000000..3141cf72d7 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSTakeScheduleItemPacket.cs @@ -0,0 +1,54 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Managers; +using AAEmu.Game.Core.Network.Game; +using AAEmu.Game.Core.Packets.G2C; +using AAEmu.Game.Models.Game.Items.Actions; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSTakeScheduleItemPacket : GamePacket +{ + public CSTakeScheduleItemPacket() : base(CSOffsets.CSTakeScheduleItemPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSTakeScheduleItemPacket"); + var itemTemplateId = stream.ReadUInt32(); + + #region ReceivedGift + + var character = Connection.ActiveChar; + // immediately change the icon + character.SendPacket(new SCScheduleItemSentPacket(itemTemplateId, false)); + + foreach (var item in character.ScheduleItems) + { + if (item.ScheduleItemId != itemTemplateId) { continue; } + + var scheduleItem = GameScheduleManager.Instance.GetScheduleItem(itemTemplateId); + var templateId = scheduleItem.ItemId; + var itemCount = scheduleItem.ItemCount; + var giveMax = scheduleItem.GiveMax; + + item.Cumulated = 0; + item.Gave++; + + if (item.Gave == giveMax) + { + Logger.Warn($"TakeScheduleItem: {character.Name}:{character.Id} didn’t receive a gift, already it to the max."); + } + else + { + character.Inventory.Bag.AcquireDefaultItem(ItemTaskType.TakeScheduleItem, templateId, (int)itemCount); + Logger.Warn($"TakeScheduleItem: {character.Name}:{character.Id} received a gift"); + } + + // Update Account Divine Clock time + AccountManager.Instance.UpdateDivineClock(character.AccountId, item.ScheduleItemId, item.Cumulated, item.Gave); + } + + #endregion + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSUpdateBountyPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSUpdateBountyPacket.cs new file mode 100644 index 0000000000..3a6668d8a4 --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSUpdateBountyPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSUpdateBountyPacket : GamePacket +{ + public CSUpdateBountyPacket() : base(CSOffsets.CSUpdateBountyPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSUpdateBountyPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/C2G/CSWithdrawMoneyPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSWithdrawMoneyPacket.cs index e6037e3817..d085103cac 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSWithdrawMoneyPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSWithdrawMoneyPacket.cs @@ -17,6 +17,6 @@ public override void Read(PacketStream stream) Logger.Debug("WithdrawMoney: amount -> {0}, aa_point -> {1}", amount, aapoint); - Connection.ActiveChar.ChangeMoney(SlotType.Bank, SlotType.Inventory, amount); + Connection.ActiveChar.ChangeMoney(SlotType.Bank, SlotType.Bag, amount); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSWorldRaycastingPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSWorldRaycastingPacket.cs new file mode 100644 index 0000000000..6b9911d3fc --- /dev/null +++ b/AAEmu.Game/Core/Packets/C2G/CSWorldRaycastingPacket.cs @@ -0,0 +1,16 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.C2G; + +public class CSWorldRaycastingPacket : GamePacket +{ + public CSWorldRaycastingPacket() : base(CSOffsets.CSWorldRaycastingPacket, 5) + { + } + + public override void Read(PacketStream stream) + { + Logger.Debug("CSWorldRaycastingPacket"); + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCAddHousePacket.cs b/AAEmu.Game/Core/Packets/G2C/SCAddHousePacket.cs new file mode 100644 index 0000000000..85a95a9be7 --- /dev/null +++ b/AAEmu.Game/Core/Packets/G2C/SCAddHousePacket.cs @@ -0,0 +1,29 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; +using AAEmu.Game.Models.Game.Housing; + +namespace AAEmu.Game.Core.Packets.G2C +{ + public class SCAddHousePacket : GamePacket + { + private readonly byte _count; + private readonly House _house; + + public SCAddHousePacket(byte count, House house) : base(SCOffsets.SCAddHousePacket, 5) + { + _count = count; + _house = house; + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write(_count); + for (var i = 0; i < _count; i++) // TODO не более 20 + { + _house.Write(stream); + } + + return stream; + } + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCAttachmentTakenPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCAttachmentTakenPacket.cs index a15e74cb9e..7d64857b43 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCAttachmentTakenPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCAttachmentTakenPacket.cs @@ -35,42 +35,24 @@ public override PacketStream Write(PacketStream stream) stream.Write(_aaPoint); stream.Write(_takeSequentially); stream.Write((byte)_itemsList.Count); + foreach (var item in _itemsList) + { + stream.Write(item.Id); + } for (var i = 0; i < 10; i++) { if (i < _itemsList.Count) { var item = _itemsList[i]; - stream.Write(item.Id); stream.Write((byte)item.SlotType); stream.Write(item.Slot); } else { - stream.Write((ulong)0); stream.Write((byte)0); stream.Write((byte)0); } } - /* - stream.Write((byte)_itemId.Length); - for (int i = 0; i < 10; i++) - { - if (_itemId.Length != 0 && i < _itemId.Length) - stream.Write(_itemId[i]); - - if (i < _itemSlots.Length) - { - stream.Write((byte)_itemSlots[i].slotType); - stream.Write(_itemSlots[i].slot); - } - else - { - stream.Write((byte)SlotType.None); - stream.Write(0); - } - } - */ - return stream; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCAuctionBidPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCAuctionBidPacket.cs index d769381561..1d5b596ed5 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCAuctionBidPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCAuctionBidPacket.cs @@ -6,21 +6,23 @@ namespace AAEmu.Game.Core.Packets.G2C; public class SCAuctionBidPacket : GamePacket { - private readonly AuctionItem _auctionItem; - public SCAuctionBidPacket(AuctionItem auctionItem) : base(SCOffsets.SCAuctionBidPacket, 5) + private readonly AuctionBid _bid; + private readonly bool _isBuyout; + private readonly uint _itemId; + + public SCAuctionBidPacket(AuctionBid bid, bool isBuyout, uint itemId) : base(SCOffsets.SCAuctionBidPacket, 5) { - _auctionItem = auctionItem; + _bid = bid; + _isBuyout = isBuyout; + _itemId = itemId; } public override PacketStream Write(PacketStream stream) { - stream.Write(_auctionItem.Id); - stream.Write(_auctionItem.BidWorldId); - stream.Write(_auctionItem.DetailType); - stream.Write(_auctionItem.BidderName); - stream.Write(_auctionItem.BidMoney); - stream.Write(_auctionItem.Duration); - stream.Write(_auctionItem.ItemId); + stream.Write(_bid); + stream.Write(_isBuyout); + stream.Write(_itemId); + return stream; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCAuctionCanceledPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCAuctionCanceledPacket.cs index 88da5c8a2c..52b8b2ac3c 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCAuctionCanceledPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCAuctionCanceledPacket.cs @@ -1,5 +1,4 @@ -using System; -using AAEmu.Commons.Network; +using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game.Auction; @@ -7,39 +6,17 @@ namespace AAEmu.Game.Core.Packets.G2C; public class SCAuctionCanceledPacket : GamePacket { - private readonly AuctionItem item; - public SCAuctionCanceledPacket(AuctionItem auctionItem) : base(SCOffsets.SCAuctionCanceledPacket, 5) + private readonly AuctionLot _auctionLot; + + public SCAuctionCanceledPacket(AuctionLot auctionLot) : base(SCOffsets.SCAuctionCanceledPacket, 5) { - item = auctionItem; + _auctionLot = auctionLot; } public override PacketStream Write(PacketStream stream) { - stream.Write(item.Id); - stream.Write(item.Duration); - stream.Write(item.ItemId); - stream.Write(item.ObjectId); - stream.Write(item.Grade); - stream.Write((byte)item.Flags); - stream.Write(item.StackSize); - stream.Write(item.DetailType); - stream.Write(DateTime.UtcNow); - stream.Write(item.LifespanMins); - stream.Write(item.Type1); - stream.Write(item.WorldId); - stream.Write(DateTime.UtcNow); - stream.Write(DateTime.UtcNow); - stream.Write(item.WorldId2); - stream.Write(item.ClientId); - stream.Write(item.ClientName); - stream.Write(item.StartMoney); - stream.Write(item.DirectMoney); - stream.Write(item.TimeLeft); - stream.Write(item.BidWorldId); - stream.Write(item.BidderId); - stream.Write(item.BidderName); - stream.Write(item.BidMoney); - stream.Write(item.Extra); + _auctionLot.Write(stream); + return stream; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCAuctionLowestPricePacket.cs b/AAEmu.Game/Core/Packets/G2C/SCAuctionLowestPricePacket.cs index fca12332dd..611c6ca386 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCAuctionLowestPricePacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCAuctionLowestPricePacket.cs @@ -1,26 +1,27 @@ using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; -using AAEmu.Game.Models.Game.Auction; namespace AAEmu.Game.Core.Packets.G2C; public class SCAuctionLowestPricePacket : GamePacket { - private readonly AuctionItem _auctionItem; + private readonly uint _itemTemplateId; + private readonly byte _itemGrade; + private readonly int _moneyAmount; - public SCAuctionLowestPricePacket(AuctionItem auctionItem) : base(SCOffsets.SCAuctionLowestPricePacket, 5) + public SCAuctionLowestPricePacket(uint itemTemplateId, byte itemGrade, int moneyAmount) : base(SCOffsets.SCAuctionLowestPricePacket, 5) { - _auctionItem = auctionItem; + _itemTemplateId = itemTemplateId; + _itemGrade = itemGrade; + _moneyAmount = moneyAmount; } public override PacketStream Write(PacketStream stream) { - stream.Write(0); //Type1? - stream.Write(0); //Type2? - if (_auctionItem != null) - stream.Write(_auctionItem.DirectMoney); - else - stream.Write(0); + stream.Write(_itemTemplateId); + stream.Write(_itemGrade); + stream.Write(_moneyAmount); + return stream; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCAuctionMessagePacket.cs b/AAEmu.Game/Core/Packets/G2C/SCAuctionMessagePacket.cs new file mode 100644 index 0000000000..18f777e76d --- /dev/null +++ b/AAEmu.Game/Core/Packets/G2C/SCAuctionMessagePacket.cs @@ -0,0 +1,28 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.G2C +{ + public class SCAuctionMessagePacket : GamePacket + { + private readonly byte _msgType; + private readonly uint _id; + private readonly int _moneyAmount; + + public SCAuctionMessagePacket(byte msgType, uint id, int moneyAmount) : base(SCOffsets.SCAuctionMessagePacket, 5) + { + _msgType = msgType; + _id = id; + _moneyAmount = moneyAmount; + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write(_msgType); + stream.Write(_id); + stream.Write(_moneyAmount); + + return stream; + } + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCAuctionPostedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCAuctionPostedPacket.cs index bb39a7a86c..733483bb97 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCAuctionPostedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCAuctionPostedPacket.cs @@ -1,5 +1,4 @@ -using System; -using AAEmu.Commons.Network; +using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game.Auction; @@ -7,41 +6,16 @@ namespace AAEmu.Game.Core.Packets.G2C; public class SCAuctionPostedPacket : GamePacket { - private readonly AuctionItem item; - public SCAuctionPostedPacket(AuctionItem auctionItem) : base(SCOffsets.SCAuctionPostedPacket, 5) + private readonly AuctionLot _auctionLot; + public SCAuctionPostedPacket(AuctionLot auctionLot) : base(SCOffsets.SCAuctionPostedPacket, 5) { - item = auctionItem; + _auctionLot = auctionLot; } public override PacketStream Write(PacketStream stream) { - stream.Write(item.Id); - stream.Write(item.Duration); - stream.Write(item.ItemId); - stream.Write(item.ObjectId); - stream.Write(item.Grade); - stream.Write((byte)item.Flags); - stream.Write(item.StackSize); - stream.Write(item.DetailType); - stream.Write(DateTime.UtcNow); - stream.Write(item.LifespanMins); - stream.Write(item.Type1); - stream.Write(item.WorldId); - stream.Write(DateTime.UtcNow); - stream.Write(DateTime.UtcNow); - stream.Write(item.WorldId2); - stream.Write(item.ClientId); - stream.Write(item.ClientName); - stream.Write(item.StartMoney); - stream.Write(item.DirectMoney); - var Random = new Random(); - var offsett = item.TimeLeft + (ulong)Random.Next(0, 10); - stream.Write(offsett); - stream.Write(item.BidWorldId); - stream.Write(item.BidderId); - stream.Write(item.BidderName); - stream.Write(item.BidMoney); - stream.Write(item.Extra); + _auctionLot.Write(stream); + return stream; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCAuctionSearchedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCAuctionSearchedPacket.cs index 3f2b4e38aa..720db3c951 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCAuctionSearchedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCAuctionSearchedPacket.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; + using AAEmu.Commons.Network; -using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game.Auction; @@ -9,59 +9,35 @@ namespace AAEmu.Game.Core.Packets.G2C; public class SCAuctionSearchedPacket : GamePacket { - private List _auctionItems; - private uint _page; - private uint _count; - //private ushort _errorMessage; - //private ulong _serverTIme; + private int _page; + private int _count; + private readonly List _lots; + private readonly short _errorMsg; + private readonly DateTime _serverTime; - public SCAuctionSearchedPacket(List auctionItems, uint page) : base(SCOffsets.SCAuctionSearchedPacket, 5) + public SCAuctionSearchedPacket(int page, int count, List lots, short errorMsg, DateTime serverTime) : + base(SCOffsets.SCAuctionSearchedPacket, 5) { - _auctionItems = auctionItems; - _count = (uint)_auctionItems.Count; _page = page; + _count = count; + _lots = lots; + _errorMsg = errorMsg; + _serverTime = serverTime; } public override PacketStream Write(PacketStream stream) { stream.Write(_page); stream.Write(_count); - Random random = new Random(); - if (_count > 0) + foreach (var lot in _lots) // TODO не более 9 { - foreach (var item in _auctionItems) - { - stream.Write(item.Id); - stream.Write(item.Duration); - stream.Write(item.ItemId); - stream.Write(item.ObjectId); - stream.Write(item.Grade); - stream.Write((byte)item.Flags); - stream.Write(item.StackSize); - stream.Write(item.DetailType); - stream.Write(DateTime.UtcNow); - stream.Write(item.LifespanMins); - stream.Write(item.Type1); - stream.Write(item.WorldId); - stream.Write(DateTime.UtcNow); - stream.Write(DateTime.UtcNow); - stream.Write(item.WorldId2); - stream.Write(item.ClientId); - stream.Write(item.ClientName); - stream.Write(item.StartMoney); - stream.Write(item.DirectMoney); - var offset = (ulong)random.Next(0, 10); //Adds offset to timeleft to prevent client from guessing it. - stream.Write(item.TimeLeft + offset); - stream.Write(item.BidWorldId); - stream.Write(item.BidderId); - stream.Write(item.BidderName); - stream.Write(item.BidMoney); - stream.Write(item.Extra); - } + lot.Write(stream); } - stream.Write((ushort)0); - stream.Write((ulong)TimeManager.Instance.GetTime); + + stream.Write(_errorMsg); + stream.Write(_serverTime); + return stream; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCAuctionSoldRecordPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCAuctionSoldRecordPacket.cs index 97f1071242..28bef186a0 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCAuctionSoldRecordPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCAuctionSoldRecordPacket.cs @@ -1,4 +1,6 @@ -using AAEmu.Commons.Network; +using System.Collections.Generic; + +using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game.Auction; @@ -6,27 +8,27 @@ namespace AAEmu.Game.Core.Packets.G2C; class SCAuctionSoldRecordPacket : GamePacket { - private readonly AuctionItem _auctionItem; - public SCAuctionSoldRecordPacket(AuctionItem auctionItem) : base(SCOffsets.SCAuctionSoldRecordPacket, 5) + private readonly uint _itemTemplateId; + private readonly byte _itemGrade; + private readonly List _solds; + + public SCAuctionSoldRecordPacket(uint itemTemplateId, byte itemGrade, List solds) : base(SCOffsets.SCAuctionSoldRecordPacket, 5) { - _auctionItem = auctionItem; - } + _itemTemplateId = itemTemplateId; + _itemGrade = itemGrade; + _solds = solds; + } public override PacketStream Write(PacketStream stream) { - stream.Write(_auctionItem.ItemId); // itemTemplateId - stream.Write(_auctionItem.Grade); // itemGrade - for (int i = 0; i < 14; i++) - { - stream.Write(_auctionItem.Id); - stream.Write(_auctionItem.BidWorldId); - stream.Write(_auctionItem.DetailType); - stream.Write(_auctionItem.BidderName); - stream.Write(_auctionItem.BidMoney); - stream.Write(_auctionItem.Duration); - stream.Write(_auctionItem.ItemId); - } + stream.Write(_itemTemplateId); // itemTemplateId + stream.Write(_itemGrade); // itemGrade - return stream; + foreach (var sold in _solds) // TODO не более 14 + { + sold.Write(stream); } -} \ No newline at end of file + + return stream; + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCCharacterLaborPowerChangedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCCharacterLaborPowerChangedPacket.cs index fb75c929f3..76f08c83cf 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCCharacterLaborPowerChangedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCCharacterLaborPowerChangedPacket.cs @@ -22,6 +22,8 @@ public SCCharacterLaborPowerChangedPacket(int amount, int action, int point, byt public override PacketStream Write(PacketStream stream) { stream.Write(_amount); + stream.Write(0); // localAmount + stream.Write(0); // rechargedAmount stream.WritePisc(_action, _point); stream.Write(_step); return stream; diff --git a/AAEmu.Game/Core/Packets/G2C/SCCompletedQuestsPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCCompletedQuestsPacket.cs index d1c7d3d74c..34b1b67b3d 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCCompletedQuestsPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCCompletedQuestsPacket.cs @@ -1,4 +1,5 @@ -using AAEmu.Commons.Network; +using System; +using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game.Quests; @@ -15,9 +16,20 @@ public SCCompletedQuestsPacket(CompletedQuest[] quests) : base(SCOffsets.SCCompl public override PacketStream Write(PacketStream stream) { - stream.Write(_quests.Length); // TODO max 200 + const int MaxQuests = 200; + if (_quests.Length > MaxQuests) + { + throw new InvalidOperationException($"Number of quests exceeds the maximum allowed ({MaxQuests})."); + } + + stream.Write(_quests.Length); foreach (var quest in _quests) { + if (quest.Body.Length != 64) // 64 / 8 = 8 байт + { + throw new InvalidOperationException("Quest body must be exactly 8 bytes."); + } + var body = new byte[8]; quest.Body.CopyTo(body, 0); diff --git a/AAEmu.Game/Core/Packets/G2C/SCCoolDownPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCCoolDownPacket.cs index 71c99cb896..a3495be7fb 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCCoolDownPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCCoolDownPacket.cs @@ -12,6 +12,7 @@ public class SCCooldownsPacket : GamePacket //private uint _skillId; private int _skillCount; private int _tagCount; + private int _chargeCount; public SCCooldownsPacket() : base(SCOffsets.SCCooldownsPacket, 5) { @@ -23,6 +24,7 @@ public SCCooldownsPacket(Character chr) : base(SCOffsets.SCCooldownsPacket, 5) _chr = chr; _skillCount = 0; _tagCount = 0; + _chargeCount = 0; } public override PacketStream Write(PacketStream stream) @@ -33,15 +35,16 @@ public override PacketStream Write(PacketStream stream) for (var i = 0; i < _skillCount; i++) { stream.Write(0u); // type(id) - stream.Write(0u); // type(id) - stream.Write(0u); // type(id) } stream.Write(_tagCount); // tagCount for (var i = 0; i < _tagCount; i++) { stream.Write(0u); // type(id) //tagId - stream.Write(0u); // type(id) // GCD? - stream.Write(0u); // type(id) // Delay? + } + stream.Write(_chargeCount); // chargeCount + for (var i = 0; i < _tagCount; i++) + { + stream.Write(0u); // type(id) //tagId } return stream; diff --git a/AAEmu.Game/Core/Packets/G2C/SCDailyCountPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCDailyCountPacket.cs new file mode 100644 index 0000000000..489fd47aa2 --- /dev/null +++ b/AAEmu.Game/Core/Packets/G2C/SCDailyCountPacket.cs @@ -0,0 +1,27 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.G2C; + +public class SCDailyCountPacket : GamePacket +{ + private readonly int _totalCount; + private readonly int _dailyCount; + private readonly int _dailyMaxCount; + + public SCDailyCountPacket(int totalCount, int dailyCount, int dailyMaxCount) : base(SCOffsets.SCDailyCountPacket, 5) + { + _totalCount = totalCount; + _dailyCount = dailyCount; + _dailyMaxCount = dailyMaxCount; + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write(_totalCount); + stream.Write(_dailyCount); + stream.Write(_dailyMaxCount); + + return stream; + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCDelayedTaskOnInGameNotifyPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCDelayedTaskOnInGameNotifyPacket.cs new file mode 100644 index 0000000000..2cc48b1376 --- /dev/null +++ b/AAEmu.Game/Core/Packets/G2C/SCDelayedTaskOnInGameNotifyPacket.cs @@ -0,0 +1,17 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.G2C; + +public class SCDelayedTaskOnInGameNotifyPacket : GamePacket +{ + public SCDelayedTaskOnInGameNotifyPacket() : base(SCOffsets.SCDelayedTaskOnInGameNotifyPacket, 5) + { + } + + public override PacketStream Write(PacketStream stream) + { + // empty body + return stream; + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCICSSyncGoodPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCICSSyncGoodPacket.cs deleted file mode 100644 index ae0fffc8d2..0000000000 --- a/AAEmu.Game/Core/Packets/G2C/SCICSSyncGoodPacket.cs +++ /dev/null @@ -1,23 +0,0 @@ -using AAEmu.Commons.Network; -using AAEmu.Game.Core.Network.Game; - -namespace AAEmu.Game.Core.Packets.G2C; - -public class SCICSSyncGoodPacket : GamePacket -{ - private readonly int _cashShopId; - private readonly int _remainCount; - - public SCICSSyncGoodPacket(int cashShopId, int remainCount) : base(SCOffsets.SCICSSyncGoodPacket, 5) - { - _cashShopId = cashShopId; - _remainCount = remainCount; - } - - public override PacketStream Write(PacketStream stream) - { - stream.Write(_cashShopId); // cashShopId - stream.Write(_remainCount); // remainCount - return stream; - } -} diff --git a/AAEmu.Game/Core/Packets/G2C/SCICSSyncGoodsPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCICSSyncGoodsPacket.cs index 1f0fdf3d3b..cd1df72877 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCICSSyncGoodsPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCICSSyncGoodsPacket.cs @@ -8,7 +8,7 @@ public class SCICSSyncGoodsPacket : GamePacket private readonly int _cashShopId; private readonly int _remainCount; - public SCICSSyncGoodsPacket(int cashShopId, int remainCount) : base(SCOffsets.SCICSSyncGoodPacket, 5) + public SCICSSyncGoodsPacket(int cashShopId, int remainCount) : base(SCOffsets.SCICSSyncGoodsPacket, 5) { _cashShopId = cashShopId; _remainCount = remainCount; @@ -20,4 +20,4 @@ public override PacketStream Write(PacketStream stream) stream.Write(_remainCount); return stream; } -} \ No newline at end of file +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCImpulseUnitPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCImpulseUnitPacket.cs new file mode 100644 index 0000000000..4b6b4d7db7 --- /dev/null +++ b/AAEmu.Game/Core/Packets/G2C/SCImpulseUnitPacket.cs @@ -0,0 +1,52 @@ +using System.Numerics; + +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; +using AAEmu.Game.Models.Game.Skills; + +namespace AAEmu.Game.Core.Packets.G2C +{ + public class SCImpulseUnitPacket : GamePacket + { + private readonly uint _objId; + private readonly SkillCaster _skillCaster; + private readonly Vector3 _vel; + private readonly Vector3 _angvel; + private readonly Vector3 _impulse; + private readonly Vector3 _angimpulse; + + public SCImpulseUnitPacket(uint objId, SkillCaster skillCaster, Vector3 vel, Vector3 angvel, Vector3 impulse, Vector3 angimpulse) : base(SCOffsets.SCImpulseUnitPacket, 5) + { + _objId = objId; + _skillCaster = skillCaster; + _vel = vel; + _angvel = angvel; + _impulse = impulse; + _angimpulse = angimpulse; + } + + public override PacketStream Write(PacketStream stream) + { + stream.WriteBc(_objId); // targetUnitId + stream.Write(_skillCaster); // skillCaster + + stream.Write(_vel.X); // Position vel + stream.Write(_vel.Y); + stream.Write(_vel.Z); + + stream.Write(_angvel.X); // Position angel + stream.Write(_angvel.Y); + stream.Write(_angvel.Z); + + stream.Write(_impulse.X); // Position impulse + stream.Write(_impulse.Y); + stream.Write(_impulse.Z); + + stream.Write(_angimpulse.X); // Position angimpulse + stream.Write(_angimpulse.Y); + stream.Write(_angimpulse.Z); + + return stream; + } + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCItemTaskNotifyPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCItemTaskNotifyPacket.cs new file mode 100644 index 0000000000..7054fbb14b --- /dev/null +++ b/AAEmu.Game/Core/Packets/G2C/SCItemTaskNotifyPacket.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; + +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; +using AAEmu.Game.Models.Game.Items.Actions; + +namespace AAEmu.Game.Core.Packets.G2C +{ + public class SCItemTaskNotifyPacket : GamePacket + { + private readonly ItemTaskType _action; + private readonly List _tasks; + private readonly List _forceRemove; + + public SCItemTaskNotifyPacket(ItemTaskType action, List tasks, List forceRemove) : base(SCOffsets.SCItemTaskNotifyPacket, 5) + { + _action = action; + _tasks = tasks; + _forceRemove = forceRemove; + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write((byte) _action); // type + + stream.Write((byte) _tasks.Count); // count TODO max count 30 + foreach (var task in _tasks) + stream.Write(task); + + stream.Write((byte) _forceRemove.Count); // TODO max count 30 + foreach (var remove in _forceRemove) + stream.Write(remove); + + stream.Write(0u); // type(id) + stream.Write(0u); // lockItemSlotKey + + return stream; + } + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCItemTaskSuccessPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCItemTaskSuccessPacket.cs index a6a1324c8c..e3623b5e71 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCItemTaskSuccessPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCItemTaskSuccessPacket.cs @@ -11,20 +11,23 @@ public class SCItemTaskSuccessPacket : GamePacket private readonly ItemTaskType _action; private readonly List _tasks; private readonly List _forceRemove; + private readonly uint _type; - public SCItemTaskSuccessPacket(ItemTaskType action, List tasks, List forceRemove) + public SCItemTaskSuccessPacket(ItemTaskType action, List tasks, List forceRemove, uint type = 0) : base(SCOffsets.SCItemTaskSuccessPacket, 5) { _action = action; _tasks = tasks; _forceRemove = forceRemove; + _type = type; } - public SCItemTaskSuccessPacket(ItemTaskType action, ItemTask task, List forceRemove) : base(SCOffsets.SCItemTaskSuccessPacket, 5) + public SCItemTaskSuccessPacket(ItemTaskType action, ItemTask task, List forceRemove, uint type = 0) : base(SCOffsets.SCItemTaskSuccessPacket, 5) { _action = action; _tasks = [task]; _forceRemove = forceRemove; + _type = type; } public override PacketStream Write(PacketStream stream) @@ -39,8 +42,9 @@ public override PacketStream Write(PacketStream stream) foreach (var remove in _forceRemove) stream.Write(remove); - stream.Write(0u); // type(id) + stream.Write(_type); // type(id) stream.Write(0u); // lockItemSlotKey + stream.Write(0u); // flags return stream; diff --git a/AAEmu.Game/Core/Packets/G2C/SCMailFailedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCMailFailedPacket.cs index c3f77a279c..6d7f6051f8 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCMailFailedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCMailFailedPacket.cs @@ -1,7 +1,7 @@ using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game.Items; -using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Core.Packets.G2C; diff --git a/AAEmu.Game/Core/Packets/G2C/SCMailStatusUpdatedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCMailStatusUpdatedPacket.cs index 8d4bb2c8c5..8727aceccf 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCMailStatusUpdatedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCMailStatusUpdatedPacket.cs @@ -1,6 +1,6 @@ using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; -using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Core.Packets.G2C; diff --git a/AAEmu.Game/Core/Packets/G2C/SCMateEquipmentChangedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCMateEquipmentChangedPacket.cs index 1f3b3cfb56..0558484ac7 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCMateEquipmentChangedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCMateEquipmentChangedPacket.cs @@ -1,5 +1,4 @@ using System; - using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game.Items; diff --git a/AAEmu.Game/Core/Packets/G2C/SCMateStatusPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCMateStatusPacket.cs index 70d2b935eb..4947f453a8 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCMateStatusPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCMateStatusPacket.cs @@ -38,7 +38,6 @@ public override PacketStream Write(PacketStream stream) { stream.Write(0u); // type } - stream.Write(_skillCount); // chargeCount for (var i = 0; i < _skillCount; i++) { diff --git a/AAEmu.Game/Core/Packets/G2C/SCOffsets.cs b/AAEmu.Game/Core/Packets/G2C/SCOffsets.cs index 5119851df3..810a3fbe3f 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCOffsets.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCOffsets.cs @@ -128,7 +128,7 @@ public static class SCOffsets public const ushort SCUnitNameChangedPacket = 0x04A; public const ushort SCUnitDeathPacket = 0x2C9; public const ushort SCUnitTeleportPacket = 0x25A; - public const ushort SCUnitBlinkPacket = 0x0C5; + public const ushort SCUnitBlinkPacket = 0x0C5; // SCBlinkUnitPacket public const ushort SCUnitAttachedPacket = 0x10C; public const ushort SCUnitDetachedPacket = 0x06D; public const ushort SCUnitInvisiblePacket = 0x049; @@ -257,7 +257,7 @@ public static class SCOffsets public const ushort SCDoodadOriginatorPacket = 0x034; public const ushort SCDoodadInteractionCallbackPacket = 0x1B1; public const ushort off_39E9B1EC = 0x1A1; - public const ushort SCMailFailPacket = 0x0DD; + public const ushort SCMailFailedPacket = 0x0DD; public const ushort SCCountUnreadMailPacket = 0x125; public const ushort SCMailSentPacket = 0x20D; public const ushort SCMailListPacket = 0x282; @@ -503,7 +503,7 @@ public static class SCOffsets public const ushort SCICSGoodDetailPacket = 0x209; public const ushort SCICSCheckTimePacket = 0x0DA; public const ushort SCICSBuyResultPacket = 0x165; - public const ushort SCICSSyncGoodPacket = 0x064; + public const ushort SCICSSyncGoodsPacket = 0x064; public const ushort SCICSCashPointPacket = 0x262; public const ushort SCBountyListPacket = 0x0B6; public const ushort SCInviteCanceledPacket = 0x00E; @@ -612,7 +612,7 @@ public static class SCOffsets public const ushort SCCurServerTimePacket = 0x03C; public const ushort SCUiTextsKeyPacket = 0x1C6; public const ushort off_39E9C878 = 0x1D1; - public const ushort off_39E9C888 = 0x114; + public const ushort SCDailyCountPacket = 0x114; // off_39E9C888 public const ushort off_39E9C898 = 0x264; public const ushort SCPremiumBonusListPacket = 0x2DF; public const ushort SCRevenueSanctionMsgPacket = 0x070; @@ -653,7 +653,7 @@ public static class SCOffsets public const ushort SCResetHeirSkillPacket = 0x0FB; public const ushort off_39E9CAF8 = 0x2F5; public const ushort off_39E9CB08 = 0x0EE; - public const ushort off_39E9CB18 = 0x0E8; + public const ushort SCSearchListPacket = 0x0E8; // off_39E9CB18 public const ushort off_39E9CB28 = 0x0A6; public const ushort off_39E9CB38 = 0x2D7; public const ushort off_39E9CB48 = 0x2FD; @@ -720,8 +720,8 @@ public static class SCOffsets public const ushort SCMailBodyPacket = 0x08A; public const ushort SCMateEquipmentChangedPacket = 0x1EC; public const ushort SCSoldItemListPacket = 0x19C; - public const ushort SCAuctionLowestPricePacket = 0x2BE; // off_39E9EA7C - public const ushort SCAuctionPostedPacket = 0x222; // off_39E9EA98 + public const ushort SCAuctionPostedPacket = 0x2BE; // off_39E9EA7C + public const ushort SCAuctionCanceledPacket = 0x222; // off_39E9EA98 public const ushort SCPlotEventPacket = 0x231; public const ushort SCActabilityPacket = 0x2B9; public const ushort SCGimmicksCreatedPacket = 0x2B3; @@ -729,7 +729,7 @@ public static class SCOffsets public const ushort off_39E9EBC0 = 0x2DB; public const ushort off_39E9EBE8 = 0x2F0; public const ushort off_39E9EC1C = 0x2BD; - public const ushort SCPortalSavedPacket = 0x066; + public const ushort SCPortalInfoSavedPacket = 0x066; // SCPortalSavedPacket public const ushort SCOtherTradeItemPutupPacket = 0x225; public const ushort SCOtherTradeitemTookdownPacket = 0x217; public const ushort SCLoadInstancePacket = 0x0E5; @@ -775,9 +775,9 @@ public static class SCOffsets public const ushort SCLootingBagPacket = 0x0F1; public const ushort SCGotMailPacket = 0x2D0; public const ushort SCChargeMoneyPaidPacket = 0x0B5; - public const ushort off_39EA2A8C = 0x1B3; - public const ushort off_39EA2A9C = 0x1AE; - public const ushort off_39EA2AAC = 0x03D; + public const ushort SCAuctionSearchedPacket = 0x1B3; // off_39EA2A8C + public const ushort SCAuctionLowestPricePacket = 0x1AE; // off_39EA2A9C + public const ushort SCAuctionMessagePacket = 0x03D; // off_39EA2AAC public const ushort SCGimmickMovementPacket = 0x11D; public const ushort SCQuestContextStartedPacket = 0x091; public const ushort SCQuestContextUpdatedPacket = 0x0D5; @@ -798,7 +798,7 @@ public static class SCOffsets public const ushort SCItemTaskSuccessPacket = 0x16B; public const ushort SCUnitBountyMoneyPacket = 0x20C; public const ushort SCFvFCombatRelationshipPacket = 0x30F; - public const ushort SCHouseStatePacket = 0x161; + public const ushort SCHouseStatePacket = 0x161; // SCMyHousePacket public const ushort off_39EA2DEC = 0x1B8; public const ushort SCSetBountyPermittedPacket = 0x2AC; public const ushort SCSetBountyDonePacket = 0x0E0; @@ -821,8 +821,8 @@ public static class SCOffsets // нет таких public const ushort SCKnockBackUnitPacket = 0xFFF; public const ushort SCMineAmountPacket = 0xFFF; - public const ushort SCOnOffSnowPacket = 0xFFF; - public const ushort SCAiAggroPacket = 0xFFF; + //public const ushort SCOnOffSnowPacket = 0xFFF; + //public const ushort SCAiAggroPacket = 0xFFF; //public const ushort SCICSGoodListPacket = 0xFFF; // SCICSGoodsListPacket public const ushort SCTrialAudienceJoinedPacket = 0xFFF; public const ushort SCItemSocketingLunastoneResultPacket = 0xFFF; @@ -846,25 +846,23 @@ public static class SCOffsets public const ushort SCLoginCharInfoHousePacket = 0xFFF; public const ushort SCTeamMemberRoleChangedPacket = 0xFFF; public const ushort SCUnitPvPPointsChangedPacket = 0xFFF; - public const ushort SCBlinkUnitPacket = 0xFFF; public const ushort SCChangeJuryOKCountPacket = 0xFFF; public const ushort SCCharBriefPacket = 0xFFF; public const ushort SCCvFCombatRelationshipPacket = 0xFFF; public const ushort SCRefreshInCharacterListPacket = 0x1DB; // то же самое, что SCRaceCongestionPacket public const ushort SCTutorialSavedPacket = 0xFFF; public const ushort SCSystemFactionListPacket = 0xFFF; - public const ushort SCSearchListPacket = 0xFFF; + //public const ushort SCSearchListPacket = 0xFFF; public const ushort SCOtherTradeItemTookdownPacket = 0xFFF; - public const ushort SCAuctionSearchedPacket = 0xFFF; + //public const ushort SCAuctionSearchedPacket = 0xFFF; public const ushort SCDominionDataPacket = 0xFFF; public const ushort SCNationalMonumentChangedPacket = 0xFFF; - public const ushort SCPortalInfoSavedPacket = 0xFFF; public const ushort SCSkillUpgradedPacket = 0xFFF; public const ushort SCTrialCancledPacket = 0xFFF; - public const ushort SCAuctionCanceledPacket = 0xFFF; + //public const ushort SCAuctionCanceledPacket = 0xFFF; public const ushort SCHousingRecoverTogglePacket = 0xFFF; - public const ushort SCMailFailedPacket = 0xFFF; + //public const ushort SCMailFailedPacket = 0xFFF; public const ushort SCItemUccDataChangedPacket = 0xFFF; - public const ushort SCMyHousePacket = 0xFFF; + public const ushort SCMyHousePacket = 0x161; // SCHouseStatePacket } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCQuestContextCompletedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCQuestContextCompletedPacket.cs index f4d0def514..360db730f7 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCQuestContextCompletedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCQuestContextCompletedPacket.cs @@ -19,7 +19,7 @@ public SCQuestContextCompletedPacket(uint questId, byte[] body, uint componentId public override PacketStream Write(PacketStream stream) { stream.Write(_questId); - stream.Write(_body); // ulong -> byte[8] + //stream.Write(_body); // ulong -> byte[8] // not in version 5070 stream.Write(_componentId); return stream; } diff --git a/AAEmu.Game/Core/Packets/G2C/SCQuestContextResetPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCQuestContextResetPacket.cs index 3adf262d25..43ddcdd53a 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCQuestContextResetPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCQuestContextResetPacket.cs @@ -19,8 +19,8 @@ public SCQuestContextResetPacket(uint questId, byte[] body, uint componentId) : public override PacketStream Write(PacketStream stream) { stream.Write(_questId); - stream.Write(_body); // ulong -> byte[8] - stream.Write(_componentId); + //stream.Write(_body); // ulong -> byte[8] // not in version 5070 + //stream.Write(_componentId); // not in version 5070 return stream; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCQuestContextStartedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCQuestContextStartedPacket.cs index ec8a784e9a..1deff02417 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCQuestContextStartedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCQuestContextStartedPacket.cs @@ -17,7 +17,7 @@ public SCQuestContextStartedPacket(Quest quest, uint componentId) : base(SCOffse public override PacketStream Write(PacketStream stream) { - stream.Write(_quest); + _quest.Write(stream); stream.Write(_componentId); return stream; } diff --git a/AAEmu.Game/Core/Packets/G2C/SCQuestContextUpdatedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCQuestContextUpdatedPacket.cs index 4a51d0f21b..483875dcea 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCQuestContextUpdatedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCQuestContextUpdatedPacket.cs @@ -26,7 +26,7 @@ public SCQuestContextUpdatedPacket(Quest quest, uint componentId, int para1 = 0, public override PacketStream Write(PacketStream stream) { - stream.Write(_quest); + _quest.Write(stream); stream.WritePiscW(5, [_componentId, _para1, _para2, _para3, _para4]); return stream; diff --git a/AAEmu.Game/Core/Packets/G2C/SCQuestsPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCQuestsPacket.cs index 88ffaade77..c8938221f0 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCQuestsPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCQuestsPacket.cs @@ -1,4 +1,5 @@ -using AAEmu.Commons.Network; +using System; +using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game.Quests; @@ -15,9 +16,17 @@ public SCQuestsPacket(Quest[] quests) : base(SCOffsets.SCQuestsPacket, 5) public override PacketStream Write(PacketStream stream) { - stream.Write(_quests.Length); // count // TODO max 20 + const int MaxQuests = 20; + if (_quests.Length > MaxQuests) + { + throw new InvalidOperationException($"Number of quests exceeds the maximum allowed ({MaxQuests})."); + } + + stream.Write(_quests.Length); // count foreach (var quest in _quests) - stream.Write(quest); + { + quest.Write(stream); + } return stream; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCRaceCongestionPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCRaceCongestionPacket.cs index e850d853cf..b2678d4d2f 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCRaceCongestionPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCRaceCongestionPacket.cs @@ -21,6 +21,8 @@ public override PacketStream Write(PacketStream stream) PRE_SELECT_RACE_FULL = 9, CHECK = 10 }*/ + stream.Write(false); // forbidCharCreating + return stream; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCRebuildHouseTaxInfoPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCRebuildHouseTaxInfoPacket.cs new file mode 100644 index 0000000000..eff68138bf --- /dev/null +++ b/AAEmu.Game/Core/Packets/G2C/SCRebuildHouseTaxInfoPacket.cs @@ -0,0 +1,50 @@ +using System; +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.G2C; + +public class SCRebuildHouseTaxInfoPacket : GamePacket +{ + private readonly ushort _tl; + private readonly int _dominionTaxRate; + private readonly int _hostileTaxRate; + private readonly int _moneyAmount; + private readonly int _moneyAmount2; + private readonly DateTime _due; + private readonly bool _isAlreadyPaid; + private readonly int _weeksWithoutPay; + private readonly int _weeksPrepay; + private readonly bool _isHeavyTaxHouse; + + public SCRebuildHouseTaxInfoPacket(ushort tl, int dominionTaxRate, int hostileTaxRate, int moneyAmount, int moneyAmount2, DateTime due, bool isAlreadyPaid, + int weeksWithoutPay, int weeksPrepay,bool isHeavyTaxHouse) : base(SCOffsets.SCRebuildHouseTaxInfoPacket, 5) + { + _tl = tl; + _dominionTaxRate = dominionTaxRate; + _hostileTaxRate = hostileTaxRate; + _moneyAmount = moneyAmount; + _moneyAmount2 = moneyAmount2; + _due = due; + _isAlreadyPaid = isAlreadyPaid; + _weeksWithoutPay = weeksWithoutPay; + _weeksPrepay = weeksPrepay; + _isHeavyTaxHouse = isHeavyTaxHouse; + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write(_tl); + stream.Write(0); // dr + stream.Write(0); // count + //for (int i = 0; i < count; i++) + //{ + // stream.Write(0); // bt + // stream.Write((byte)0); // vt + // stream.Write(0f); // pd + // stream.Write(0); // wp + // stream.Write(0); // dtr + //} + return stream; + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCReputationChangedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCReputationChangedPacket.cs new file mode 100644 index 0000000000..684a531b0d --- /dev/null +++ b/AAEmu.Game/Core/Packets/G2C/SCReputationChangedPacket.cs @@ -0,0 +1,26 @@ +using System; + +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.G2C; + +public class SCReputationChangedPacket : GamePacket +{ + private readonly DateTime _reputationUpdated; + private readonly bool _weeklyReset; + + public SCReputationChangedPacket(DateTime reputationUpdated, bool weeklyReset) : base(SCOffsets.SCReputationChangedPacket, 5) + { + _reputationUpdated = reputationUpdated; + _weeklyReset = weeklyReset; + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write(_reputationUpdated); + stream.Write(_weeklyReset); + + return stream; + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCScheduleItemSentPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCScheduleItemSentPacket.cs new file mode 100644 index 0000000000..f9644cb2d1 --- /dev/null +++ b/AAEmu.Game/Core/Packets/G2C/SCScheduleItemSentPacket.cs @@ -0,0 +1,23 @@ +using AAEmu.Commons.Network; +using AAEmu.Game.Core.Network.Game; + +namespace AAEmu.Game.Core.Packets.G2C; + +public class SCScheduleItemSentPacket : GamePacket +{ + private readonly uint _itemTemplateId; + private readonly bool _byMail; + + public SCScheduleItemSentPacket(uint itemTemplateId, bool byMail) : base(SCOffsets.SCScheduleItemSentPacket, 5) + { + _itemTemplateId = itemTemplateId; + _byMail = byMail; + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write(_itemTemplateId); + stream.Write(_byMail); + return stream; + } +} diff --git a/AAEmu.Game/Core/Packets/G2C/SCScheduleItemUpdatePacket.cs b/AAEmu.Game/Core/Packets/G2C/SCScheduleItemUpdatePacket.cs index 83dcbd6303..7b1c64242b 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCScheduleItemUpdatePacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCScheduleItemUpdatePacket.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; + using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game; @@ -16,7 +17,7 @@ public SCScheduleItemUpdatePacket(List scheduleItems) : base(SCOff public override PacketStream Write(PacketStream stream) { - stream.Write(_scheduleItems.Count); + stream.Write((byte)_scheduleItems.Count); foreach (var item in _scheduleItems) { stream.Write(item); diff --git a/AAEmu.Game/Core/Packets/G2C/SCSkillCooldownResetPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCSkillCooldownResetPacket.cs index 63d1415e76..9b5d3bddad 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCSkillCooldownResetPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCSkillCooldownResetPacket.cs @@ -10,29 +10,38 @@ public class SCSkillCooldownResetPacket : GamePacket private uint _skillId; private uint _tagId; private bool _gcd; + private bool _rstc; + private bool _rtsc; + private bool _rtstc; public SCSkillCooldownResetPacket() : base(SCOffsets.SCSkillCooldownResetPacket, 5) { } - public SCSkillCooldownResetPacket(Character chr, uint skillId, uint tagId, bool gcd) : base(SCOffsets.SCSkillCooldownResetPacket, 5) + public SCSkillCooldownResetPacket(Character chr, uint skillId, uint tagId, bool gcd, bool rstc = false, bool rtsc = false, bool rtstc = false) : base(SCOffsets.SCSkillCooldownResetPacket, 5) { _skillId = skillId; _tagId = tagId; _gcd = gcd; _chr = chr; _gcd = gcd; + _rstc = rstc; + _rtsc = rtsc; + _rtstc = rtstc; } public override PacketStream Write(PacketStream stream) { //TODO заготовка для пакета - stream.WriteBc(_chr.ObjId); //unitId - stream.Write(_skillId); //skillId - stream.Write(_tagId); //tagId - stream.Write(_gcd); //gcd - Trigger GCD + stream.WriteBc(_chr.ObjId); // unitId + stream.Write(_skillId); // skillId + stream.Write(_tagId); // tagId + stream.Write(_gcd); // gcd - Trigger GCD + stream.Write(_gcd); // rstc + stream.Write(_gcd); // rtsc + stream.Write(_gcd); // rtstc return stream; } diff --git a/AAEmu.Game/Core/Packets/G2C/SCSkillFiredPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCSkillFiredPacket.cs index 9a493a19a6..8ae17e4765 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCSkillFiredPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCSkillFiredPacket.cs @@ -6,6 +6,7 @@ using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Skills; +using AAEmu.Game.Models.Game.Skills.Static; using AAEmu.Game.Models.Game.Units; namespace AAEmu.Game.Core.Packets.G2C; @@ -61,6 +62,11 @@ public class SCSkillFiredPacket : GamePacket private static Queue NpcFireAnimQueue; public short ComputedDelay { get; set; } + private ExtraDataFlags ExtraDataFlag { get; set; } + private byte ExtraDataByte { get; set; } + private ushort ExtraDataUShort { get; set; } + private uint ExtraDataUInt { get; set; } + private bool ExtraDataBool { get; set; } public SCSkillFiredPacket(uint id, ushort tl, SkillCaster caster, SkillCastTarget target, Skill skill, SkillObject skillObject, BaseUnit baseUnit) : base(SCOffsets.SCSkillFiredPacket, 5) @@ -120,6 +126,52 @@ public SCSkillFiredPacket(uint id, ushort tl, SkillCaster caster, SkillCastTarge } } + public SCSkillFiredPacket(uint id, ushort tl, SkillCaster caster, SkillCastTarget target, Skill skill, SkillObject skillObject) + : base(SCOffsets.SCSkillFiredPacket, 5) + { + _id = id; + _tl = tl; + _caster = caster; + _target = target; + _skill = skill; + _skillObject = skillObject; + } + + public SCSkillFiredPacket(uint id, ushort tl, SkillCaster caster, SkillCastTarget target, Skill skill, SkillObject skillObject, short effectDelay = 37, int fireAnimId = 2, bool dist = true) + : base(SCOffsets.SCSkillFiredPacket, 5) + { + _id = id; + _tl = tl; + _caster = caster; + _target = target; + _skill = skill; + _skillObject = skillObject; + _effectDelay = effectDelay; + _fireAnimId = fireAnimId; + _dist = dist; + } + + public override PacketStream Write(PacketStream stream) + { + //stream.Write(_id); // st - skill type removed in 3.0.3.0 + stream.Write(_tl); // sid - skill id + + stream.Write(_caster); // SkillCaster + stream.Write(_target); // SkillCastTarget + stream.Write(_skillObject); // SkillObject + + if (_character is not null) + { + WriteCharacterSkillData(stream); + } + else + { + WriteNpcSkillData(stream); + } + + return stream; + } + private int GetNextAnimationId() { if (_character is not null) @@ -192,52 +244,6 @@ private void MergeDictionaries(Dictionary target, Dictionary } } - public SCSkillFiredPacket(uint id, ushort tl, SkillCaster caster, SkillCastTarget target, Skill skill, SkillObject skillObject) - : base(SCOffsets.SCSkillFiredPacket, 5) - { - _id = id; - _tl = tl; - _caster = caster; - _target = target; - _skill = skill; - _skillObject = skillObject; - } - - public SCSkillFiredPacket(uint id, ushort tl, SkillCaster caster, SkillCastTarget target, Skill skill, SkillObject skillObject, short effectDelay = 37, int fireAnimId = 2, bool dist = true) - : base(SCOffsets.SCSkillFiredPacket, 5) - { - _id = id; - _tl = tl; - _caster = caster; - _target = target; - _skill = skill; - _skillObject = skillObject; - _effectDelay = effectDelay; - _fireAnimId = fireAnimId; - _dist = dist; - } - - public override PacketStream Write(PacketStream stream) - { - //stream.Write(_id); // st - skill type removed in 3.0.3.0 - stream.Write(_tl); // sid - skill id - - stream.Write(_caster); // SkillCaster - stream.Write(_target); // SkillCastTarget - stream.Write(_skillObject); // SkillObject - - if (_character is not null) - { - WriteCharacterSkillData(stream); - } - else - { - WriteNpcSkillData(stream); - } - - return stream; - } - private void WriteCharacterSkillData(PacketStream stream) { if (_skill.Template.Id == 2) @@ -248,8 +254,14 @@ private void WriteCharacterSkillData(PacketStream stream) // автоатака stream.Write((short)0); stream.Write((short)0); - stream.Write((byte)1); // f - When changed to 1 when firing an auto-casting skill, will make the little blue arrow. - stream.Write((byte)15); // c + + //stream.Write((byte)1); // f - When changed to 1 when firing an auto-casting skill, will make the little blue arrow. + //stream.Write((byte)15); // c + + ExtraDataFlag = ExtraDataFlags.HasByte; + SetSkillResult(SkillResult.TooFarRange); // ExtraDataByte = 15; + WriteExtraData(stream); + stream.WritePisc(_id, 0); // added skill type here in 3.0.3.0 stream.Write((byte)0); // flag } @@ -258,7 +270,10 @@ private void WriteCharacterSkillData(PacketStream stream) // отдельные удары stream.Write((short)FireAnimData[_fireAnimId]); // выставляем время для ближнего боя в зависимости от анимации stream.Write((short)0); - stream.Write((byte)0); // f - When changed to 1 when firing an auto-casting skill, will make the little blue arrow. + + //stream.Write((byte)0); // f - When changed to 1 when firing an auto-casting skill, will make the little blue arrow. + WriteExtraData(stream); + stream.WritePisc(_id, _fireAnimId); // added skill type here in 3.0.3.0 stream.Write((byte)0); // flag } @@ -268,7 +283,10 @@ private void WriteCharacterSkillData(PacketStream stream) // дальняя атака stream.Write((short)(ComputedDelay / 10 + 10)); // TODO +10 It became visible flying arrows stream.Write((short)(_skill.Template.ChannelingTime / 10 + 10)); - stream.Write((byte)0); // f - When changed to 1 when firing an auto-casting skill, will make the little blue arrow. + + //stream.Write((byte)0); // f - When changed to 1 when firing an auto-casting skill, will make the little blue arrow. + WriteExtraData(stream); + stream.WritePisc(_id, _skill.Template.FireAnim?.Id ?? 0); // added skill type here in 3.0.3.0 stream.Write((byte)0); // flag } @@ -281,7 +299,10 @@ private void WriteNpcSkillData(PacketStream stream) // ближняя атака stream.Write((short)NpcFireAnimData[_fireAnimId]); // выставляем время для ближнего боя в зависимости от анимации stream.Write((short)0); - stream.Write((byte)0); // f - When changed to 1 when firing an auto-casting skill, will make the little blue arrow. + + //stream.Write((byte)0); // f - When changed to 1 when firing an auto-casting skill, will make the little blue arrow. + WriteExtraData(stream); + stream.WritePisc(_id, _fireAnimId); // added skill type here in 3.0.3.0 stream.Write((byte)0); // flag } @@ -290,9 +311,74 @@ private void WriteNpcSkillData(PacketStream stream) // дальняя атака stream.Write((short)(ComputedDelay / 10 + 10)); // TODO +10 It became visible flying arrows stream.Write((short)(_skill.Template.ChannelingTime / 10 + 10)); - stream.Write((byte)0); // f - When changed to 1 when firing an auto-casting skill, will make the little blue arrow. + + //stream.Write((byte)0); // f - When changed to 1 when firing an auto-casting skill, will make the little blue arrow. + WriteExtraData(stream); + stream.WritePisc(_id, _skill.Template.FireAnim?.Id ?? 0); // added skill type here in 3.0.3.0 stream.Write((byte)0); // flag } } + + private void WriteExtraData(PacketStream stream) + { + stream.Write((byte)ExtraDataFlag); // f + if (ExtraDataFlag.HasFlag(ExtraDataFlags.HasByte)) + stream.Write(ExtraDataByte); // c + if (ExtraDataFlag.HasFlag(ExtraDataFlags.HasUShort)) + stream.Write(ExtraDataUShort); // e + if (ExtraDataFlag.HasFlag(ExtraDataFlags.HasUInt)) + stream.Write(ExtraDataUInt); // p + if (ExtraDataFlag.HasFlag(ExtraDataFlags.HasBool)) + stream.Write(ExtraDataBool); // d + } + + public SCSkillFiredPacket SetSkillResult(SkillResult skillResult) + { + if (skillResult != SkillResult.Success) + ExtraDataFlag |= ExtraDataFlags.HasByte; + else + ExtraDataFlag &= ~ExtraDataFlags.HasByte; + ExtraDataByte = (byte)skillResult; + + return this; + } + + public SCSkillFiredPacket SetResultUShort(ushort val) + { + if (val != 0) + ExtraDataFlag |= ExtraDataFlags.HasUShort; + else + ExtraDataFlag &= ~ExtraDataFlags.HasUShort; + ExtraDataUShort = val; + + return this; + } + + public SCSkillFiredPacket SetResultUInt(uint val) + { + if (val != 0) + ExtraDataFlag |= ExtraDataFlags.HasUInt; + else + ExtraDataFlag &= ~ExtraDataFlags.HasUInt; + ExtraDataUInt = val; + + return this; + } + + public SCSkillFiredPacket SetResultBool(bool val) + { + if (val != false) + ExtraDataFlag |= ExtraDataFlags.HasBool; + else + ExtraDataFlag &= ~ExtraDataFlags.HasBool; + ExtraDataBool = val; + + return this; + } + + public override string Verbose() + { + return $" - Id {_id}, TlId {_tl}, Caster {_caster.ObjId}, Target {_target.ObjId}, Skill {_skill.Template.Id}"; + } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCSkillLearnedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCSkillLearnedPacket.cs index 8a05b59385..7fc50b0748 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCSkillLearnedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCSkillLearnedPacket.cs @@ -16,7 +16,7 @@ public SCSkillLearnedPacket(Skill skill) : base(SCOffsets.SCSkillLearnedPacket, public override PacketStream Write(PacketStream stream) { stream.Write(_skill.Id); - stream.Write(_skill.Level); + //stream.Write(_skill.Level); // removed in 5.0.7.0 return stream; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCSkillStartedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCSkillStartedPacket.cs index fccd7fa2b9..12a5d1ef20 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCSkillStartedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCSkillStartedPacket.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; + using AAEmu.Commons.Network; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Models.Game.Skills; @@ -13,6 +13,7 @@ public enum ExtraDataFlags HasByte = 1, HasUShort = 2, HasUInt = 4, + HasBool = 8 } public class SCSkillStartedPacket : GamePacket @@ -33,6 +34,7 @@ public class SCSkillStartedPacket : GamePacket private byte ExtraDataByte { get; set; } private ushort ExtraDataUShort { get; set; } private uint ExtraDataUInt { get; set; } + private bool ExtraDataBool { get; set; } public SCSkillStartedPacket(uint id, ushort tl, SkillCaster caster, SkillCastTarget target, Skill skill, SkillObject skillObject) : base(SCOffsets.SCSkillStartedPacket, 5) @@ -47,23 +49,32 @@ public SCSkillStartedPacket(uint id, ushort tl, SkillCaster caster, SkillCastTar public override PacketStream Write(PacketStream stream) { - stream.Write(_id); - stream.Write(_tl); + stream.Write(_id); // st + stream.Write(_tl); // sid stream.Write(_caster); stream.Write(_target); stream.Write(_skillObject); stream.Write(RealCastTimeDiv10); stream.Write(BaseCastTimeDiv10); - stream.Write(CastSynergy); // castSynergy // (short)0 + + stream.Write(CastSynergy); // castSynergy (bool) // (short)0 + + WriteExtraData(stream); + return stream; + } + + private void WriteExtraData(PacketStream stream) + { stream.Write((byte)ExtraDataFlag); // f if (ExtraDataFlag.HasFlag(ExtraDataFlags.HasByte)) - stream.Write(ExtraDataByte); + stream.Write(ExtraDataByte); // c if (ExtraDataFlag.HasFlag(ExtraDataFlags.HasUShort)) - stream.Write(ExtraDataUShort); + stream.Write(ExtraDataUShort); // e if (ExtraDataFlag.HasFlag(ExtraDataFlags.HasUInt)) - stream.Write(ExtraDataUInt); - return stream; + stream.Write(ExtraDataUInt); // p + if (ExtraDataFlag.HasFlag(ExtraDataFlags.HasBool)) + stream.Write(ExtraDataBool); // d } public SCSkillStartedPacket SetSkillResult(SkillResult skillResult) @@ -98,6 +109,17 @@ public SCSkillStartedPacket SetResultUInt(uint val) return this; } + + public SCSkillStartedPacket SetResultBool(bool val) + { + if (val != false) + ExtraDataFlag |= ExtraDataFlags.HasBool; + else + ExtraDataFlag &= ~ExtraDataFlags.HasBool; + ExtraDataBool = val; + + return this; + } public override string Verbose() { diff --git a/AAEmu.Game/Core/Packets/G2C/SCSkillStopped.cs b/AAEmu.Game/Core/Packets/G2C/SCSkillStopped.cs deleted file mode 100644 index a81edec528..0000000000 --- a/AAEmu.Game/Core/Packets/G2C/SCSkillStopped.cs +++ /dev/null @@ -1,25 +0,0 @@ -//using AAEmu.Commons.Network; -//using AAEmu.Game.Core.Network.Game; - -//namespace AAEmu.Game.Core.Packets.G2C; - -//public class SCSkillStoppedPacket : GamePacket -//{ -// public override PacketLogLevel LogLevel => PacketLogLevel.Trace; - -// private readonly uint _unitObjId; -// private readonly uint _skillId; - -// public SCSkillStoppedPacket(uint unitObjId, uint skillId) : base(SCOffsets.SCSkillStoppedPacket, 5) -// { -// _unitObjId = unitObjId; -// _skillId = skillId; -// } - -// public override PacketStream Write(PacketStream stream) -// { -// stream.WriteBc(_unitObjId); -// stream.Write(_skillId); -// return stream; -// } -//} diff --git a/AAEmu.Game/Core/Packets/G2C/SCSlaveStatusPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCSlaveStatusPacket.cs index 8678d9c210..0925165fec 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCSlaveStatusPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCSlaveStatusPacket.cs @@ -19,6 +19,7 @@ public SCSlaveStatusPacket(Slave slave) : base(SCOffsets.SCSlaveStatusPacket, 5) _slave = slave; } + public override PacketStream Write(PacketStream stream) { stream.WriteBc(_slave.ObjId); // bc @@ -27,19 +28,17 @@ public override PacketStream Write(PacketStream stream) #region skill&tag stream.Write(_skillCount); // skillCount - + // TODO я считаю, что в итоге требуется выводить все скиллы, тэги и чарджи for (var i = 0; i < _skillCount; i++) { stream.Write(_slave.Skills[i]); // type } - stream.Write(_tagCount); // tagCount for (var i = 0; i < _tagCount; i++) { stream.Write(0u); // type } - stream.Write(_chargeCount); // chargeCount for (var i = 0; i < _skillCount; i++) { diff --git a/AAEmu.Game/Core/Packets/G2C/SCSoldItemListPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCSoldItemListPacket.cs index c1cdba389a..d7af947c93 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCSoldItemListPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCSoldItemListPacket.cs @@ -17,7 +17,7 @@ public SCSoldItemListPacket(List items) : base(SCOffsets.SCSoldItemListPac var size = items.Count - startPos; _items.AddRange(items.GetRange(startPos, size)); */ - _items.AddRange(items.GetRange(0, items.Count > 12 ? 12 : items.Count)); + _items.AddRange(items.GetRange(0, items.Count > 16 ? 16 : items.Count)); } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Core/Packets/G2C/SCBlinkUnitPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCUnitBlinkPacket.cs similarity index 64% rename from AAEmu.Game/Core/Packets/G2C/SCBlinkUnitPacket.cs rename to AAEmu.Game/Core/Packets/G2C/SCUnitBlinkPacket.cs index ebbf901827..3a36cc4b49 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCBlinkUnitPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCUnitBlinkPacket.cs @@ -4,7 +4,7 @@ namespace AAEmu.Game.Core.Packets.G2C; -public class SCBlinkUnitPacket : GamePacket +public class SCUnitBlinkPacket : GamePacket { private readonly uint _objId; private readonly float _distance; @@ -13,7 +13,7 @@ public class SCBlinkUnitPacket : GamePacket private readonly float _y; private readonly float _z; - public SCBlinkUnitPacket(uint objId, float distance, float degree, float x, float y, float z) : base(SCOffsets.SCBlinkUnitPacket, 5) + public SCUnitBlinkPacket(uint objId, float distance, float degree, float x, float y, float z) : base(SCOffsets.SCUnitBlinkPacket, 5) { _objId = objId; _distance = distance; @@ -25,10 +25,10 @@ public SCBlinkUnitPacket(uint objId, float distance, float degree, float x, floa public override PacketStream Write(PacketStream stream) { - stream.WriteBc(_objId); - stream.Write(_distance); - stream.Write(_degree); - stream.Write(Helpers.ConvertLongX(_x)); + stream.WriteBc(_objId); // unitId + stream.Write(_distance); // distance + stream.Write(_degree); // degree + stream.Write(Helpers.ConvertLongX(_x)); // readPosXYZ stream.Write(Helpers.ConvertLongY(_y)); stream.Write(_z); return stream; diff --git a/AAEmu.Game/Core/Packets/G2C/SCUnitEquipmentsChangedPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCUnitEquipmentsChangedPacket.cs index 0c6b4a0eee..5c4538d3b9 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCUnitEquipmentsChangedPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCUnitEquipmentsChangedPacket.cs @@ -37,9 +37,9 @@ public override PacketStream Write(PacketStream stream) else { stream.Write(item); - var v15 = (int)item.ItemFlags << index; - ++index; - ItemFlags |= v15; + //var v15 = (int)item.ItemFlags << index; + //++index; + //ItemFlags |= v15; } } diff --git a/AAEmu.Game/Core/Packets/G2C/SCUnitStatePacket.cs b/AAEmu.Game/Core/Packets/G2C/SCUnitStatePacket.cs index d285bdba2c..f11025c25e 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCUnitStatePacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCUnitStatePacket.cs @@ -363,7 +363,7 @@ public override PacketStream Write(PacketStream stream) { stream.WritePisc(0, 0, 0, 0); // TODO второе число больше нуля, что это за число? stream.WritePisc((uint)(_unit.Faction?.Id ?? 0), (uint)(_unit.Expedition?.Id ?? 0), 0, 0); // pisc - stream.WritePisc(0, 0, 0, 0); // pisc + stream.WritePisc(0, 255, 0, 0); // pisc } switch (_unit) @@ -386,14 +386,14 @@ public override PacketStream Write(PacketStream stream) * 0x0004 - 6bit - невидимость? * 0x0008 - 5bit - дуэль * 0x0010 - 4bit - + * 0x0020 * 0x0040 - 2bit - gmmode, дополнительно 7 байт * 0x0080 - 1bit - дополнительно tl(ushort), tl(ushort), tl(ushort), tl(ushort) - * 0x0020 - * 0x0200 * 0x0100 - 16bit - дополнительно 3 байт (bc), firstHitterTeamId(uint) + * 0x0200 * 0x0400 - 14bit - надпись "Отсутсвует" под именем - * 0x1000 * 0x0800 + * 0x1000 */ break; } @@ -484,7 +484,7 @@ public override PacketStream Write(PacketStream stream) #region Stats var size = 1u; - stream.Write(size); // size + //stream.Write(size); // size for (var i = 0; i < size; i++) { for (var j = 0; j < 5; j++) diff --git a/AAEmu.Game/Core/Packets/G2C/SCUpdateSkillActiveTypePacket.cs b/AAEmu.Game/Core/Packets/G2C/SCUpdateSkillActiveTypePacket.cs index 67b36f78e5..a8ce0092f4 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCUpdateSkillActiveTypePacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCUpdateSkillActiveTypePacket.cs @@ -6,20 +6,23 @@ namespace AAEmu.Game.Core.Packets.G2C; public class SCUpdateSkillActiveTypePacket : GamePacket { + private readonly uint _heirSkillType; private readonly uint _skillId; private readonly AbilityType _ability; - public SCUpdateSkillActiveTypePacket(uint skillId, AbilityType ability) : base(SCOffsets.SCUpdateSkillActiveTypePacket, 5) + public SCUpdateSkillActiveTypePacket(uint heirSkillType, uint skillId, AbilityType ability) : base(SCOffsets.SCUpdateSkillActiveTypePacket, 5) { + _heirSkillType = heirSkillType; _skillId = skillId; _ability = ability; } public override PacketStream Write(PacketStream stream) { - stream.Write(_skillId); // skillType (type) - stream.Write((byte)_ability); // ability + stream.Write(_heirSkillType); // heirSkillType + stream.Write(_skillId); // skillType + stream.Write((byte)_ability); // activeType return stream; } -} \ No newline at end of file +} diff --git a/AAEmu.Game/Core/Packets/Proxy/FinishStatePacket.cs b/AAEmu.Game/Core/Packets/Proxy/FinishStatePacket.cs index 19f7aa5928..fa3cd1edd6 100644 --- a/AAEmu.Game/Core/Packets/Proxy/FinishStatePacket.cs +++ b/AAEmu.Game/Core/Packets/Proxy/FinishStatePacket.cs @@ -35,7 +35,7 @@ public override void Read(PacketStream stream) Connection.SendPacket(new SetGameTypePacket(levelname, 0, 1)); // TODO - level Connection.SendPacket(new SCInitialConfigPacket()); // added in 5.0.7.0 - Connection.SendPacket(new SCTowerConfigPacket()); + //Connection.SendPacket(new SCTowerConfigPacket()); // Test URLs // Original Trion values // Client treats these as folders and will add a trailing slash (/) with whatever it needs diff --git a/AAEmu.Game/Data/Worlds/instance_carcass/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_carcass/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_carcass/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_carcass/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_carcass/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_carcass/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_challenge_tower/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_challenge_tower/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_challenge_tower/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_challenge_tower/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_challenge_tower/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_challenge_tower/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_defense_of_feast/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_defense_of_feast/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_defense_of_feast/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_defense_of_feast/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_defense_of_feast/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_defense_of_feast/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_dew_plain/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_dew_plain/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_dew_plain/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_dew_plain/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_dew_plain/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_dew_plain/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_dewplane_boss/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_dewplane_boss/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_dewplane_boss/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_dewplane_boss/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_dewplane_boss/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_dewplane_boss/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_eternity/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_eternity/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_eternity/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_eternity/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_eternity/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_eternity/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_golden_plains/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_golden_plains/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_golden_plains/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_golden_plains/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_golden_plains/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_golden_plains/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_golden_plains_war/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_golden_plains_war/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_golden_plains_war/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_golden_plains_war/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_golden_plains_war/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_golden_plains_war/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_hanging_gardens_of_ipna/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_hanging_gardens_of_ipna/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_hanging_gardens_of_ipna/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_hanging_gardens_of_ipna/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_hanging_gardens_of_ipna/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_hanging_gardens_of_ipna/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_library_new/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_library_new/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_library_new/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_library_new/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_library_new/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_library_new/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_library_new_boss/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_library_new_boss/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_library_new_boss/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_library_new_boss/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_library_new_boss/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_library_new_boss/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_sal_temple_hard/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_sal_temple_hard/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_sal_temple_hard/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_sal_temple_hard/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_sal_temple_hard/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_sal_temple_hard/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_sea_survival/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_sea_survival/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_sea_survival/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_sea_survival/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_sea_survival/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_sea_survival/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_sea_survival_2/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_sea_survival_2/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_sea_survival_2/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_sea_survival_2/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_sea_survival_2/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_sea_survival_2/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_sea_survival_4/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_sea_survival_4/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_sea_survival_4/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_sea_survival_4/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_sea_survival_4/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_sea_survival_4/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_the_last_day_of_hiramakand/doodad_spawns.json b/AAEmu.Game/Data/Worlds/instance_the_last_day_of_hiramakand/doodad_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_the_last_day_of_hiramakand/doodad_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/Worlds/instance_the_last_day_of_hiramakand/npc_spawns.json b/AAEmu.Game/Data/Worlds/instance_the_last_day_of_hiramakand/npc_spawns.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/AAEmu.Game/Data/Worlds/instance_the_last_day_of_hiramakand/npc_spawns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/AAEmu.Game/Data/housing_bindings.json b/AAEmu.Game/Data/housing_bindings.json index c19144b4aa..defb6fbffc 100644 --- a/AAEmu.Game/Data/housing_bindings.json +++ b/AAEmu.Game/Data/housing_bindings.json @@ -1,1083 +1,3043 @@ [ -/* - TemplateId=1927 -> 'modeld' -> - sub_id=820 -> 'prefab_elements' -> - 820 & state=1 -> id=3936 => file_path - file_path = housing_tree.xml - in the housing_tree.xml file we look for - housing_tree_pink.tree_body and select points from - house_tree_out.cgf.dump, - housing_tree_base.cgf.dump - tree_stair.cgf.dump, - housing_tree_in.cgf.dump, - housing_tree_stair.cgf.dump - (dump obtained using RC) -*/ - { - "TemplateId": [ - 41, - 42, - 43, - 90, - 92, - 279 - ], - "AttachPointId": { - "1": { - "X": 0, - "Y": 0, - "Z": 0.7337 - }, - "57": { - "X": 2.5215, - "Y": 0.3047, - "Z": 4.0921 - } - } - }, - { - "TemplateId": [ - 89 - ], - "AttachPointId": { - "57": { - "X": 0, - "Y": 0, - "Z": 2.3314 - } - } - }, - { - "TemplateId": [ - 136, - 137, - 138 - ], - "AttachPointId": { - "1": { - "X": 0, - "Y": -18.8, - "Z": 3 - }, - "36": { - "X": 0, - "Y": 3.1308, - "Z": 1 - }, - "37": { - "X": 0, - "Y": 3.1308, - "Z": 8 - }, - "38": { - "X": 7.1503, - "Y": 0.25, - "Z": 2.5995 - }, - "39": { - "X": -7.1503, - "Y": 0.25, - "Z": 2.5995 - }, - "40": { - "X": -9.3, - "Y": -9.0582, - "Z": 2.5995 - }, - "41": { - "X": 9.3, - "Y": -9.0582, - "Z": 2.5995 - }, - "57": { - "X": 3.35, - "Y": 3.85, - "Z": 5 - } - } - }, - { - "TemplateId": [ - 157 - ], - "AttachPointId": { - "57": { - "X": 0, - "Y": 0, - "Z": 1.5 - } - } - }, - { - "TemplateId": [ - 171 - ], - "AttachPointId": { - "36": { - "X": -0.0078, - "Y": 4.0977, - "Z": 2.5995 - }, - "38": { - "X": 2.7891, - "Y": 4.1348, - "Z": 2.6845 - }, - "37": { - "X": -2.7891, - "Y": 4.1348, - "Z": 2.6845 - }, - "57": { - "X": 0, - "Y": 4.209, - "Z": 5.2175 - }, - "1": { - "X": -3.0977, - "Y": -1.9120, - "Z": 0.7197 - }, - "9": { - "X": 3.3984, - "Y": 5.8613, - "Z": 1.0128 - } - } - }, - { - "TemplateId": [ - 172, - 173, - 174, - 175, - 176, - 177, - 178, - 179, - 180 - ], - "AttachPointId": { - "1": { - "X": -3.0976, - "Y": -1.9121, - "Z": 0.7196 - }, - "24": { - "X": 0, - "Y": 7.004, - "Z": -3.7260 - }, - "36": { - "X": -0.0078, - "Y": 4.0977, - "Z": 2.5995 - }, - "37": { - "X": -2.8086, - "Y": 4.1347, - "Z": 2.6845 - }, - "38": { - "X": 2.789, - "Y": 4.1348, - "Z": 2.6844 - }, - "57": { - "X": 0, - "Y": 4.209, - "Z": 5.2175 - } - } - }, - { - "TemplateId": [ - 181 - ], - "AttachPointId": { - "1": { - "X": -0.0527, - "Y": -3.1464, - "Z": 0.8227 - }, - "24": { - "X": 0, - "Y": 8.2812, - "Z": -4.7455 - }, - "36": { - "X": -0.0039, - "Y": 4.1054, - "Z": 2.7005 - }, - "37": { - "X": -2.8046, - "Y": 4.0683, - "Z": 2.8866 - }, - "38": { - "X": 2.7949, - "Y": 4.0683, - "Z": 2.8866 - }, - "57": { - "X": 0.0273, - "Y": 4.6054, - "Z": 5.2055 - } - } - }, - { - "TemplateId": [ - 182 - ], - "AttachPointId": { - "1": { - "X": -7.4, - "Y": -1.95, - "Z": 1 - }, - "36": { - "X": -4.2070, - "Y": 4.082, - "Z": 2.5995 - }, - "37": { - "X": -7.0078, - "Y": 4.1621, - "Z": 2.6845 - }, - "38": { - "X": -1.4082, - "Y": 4.1621, - "Z": 2.6845 - }, - "57": { - "X": -4.2168, - "Y": 4.2129, - "Z": 5.2706 - } - } - }, - { - "TemplateId": [ - 183 - ], - "AttachPointId": { - "1": { - "X": 7.2632, - "Y": -2.1, - "Z": 1 - }, - "36": { - "X": -5.59, - "Y": 8.3085, - "Z": 2.5995 - }, - "37": { - "X": 1.40, - "Y": 8.244, - "Z": 2.5995 - }, - "38": { - "X": 4.1914, - "Y": 8.244, - "Z": 2.5995 - }, - "39": { - "X": -8.2597, - "Y": 2.7968, - "Z": 2.5995 - }, - "40": { - "X": -8.2597, - "Y": -2.8027, - "Z": 2.5995 - }, - "41": { - "X": -4.19, - "Y": 0, - "Z": 8 - }, - "42": { - "X": 4.2128, - "Y": 8.25, - "Z": 8.7 - }, - "43": { - "X": -8.2441, - "Y": -2.8, - "Z": 8 - }, - "44": { - "X": -8.2441, - "Y": -5.6, - "Z": 8 - }, - "57": { - "X": -5.59, - "Y": 8.7, - "Z": 5.2706 - } - } - }, - { - "TemplateId": [ - 193, - 194, - 195, - 196, - 197, - 198, - 199, - 200, - 201 - ], - "AttachPointId": { - "1": { - "X": -4.2597, - "Y": -3.1738, - "Z": 0.7177 - }, - "36": { - "X": -4.2070, - "Y": 4.082, - "Z": 2.5995 - }, - "37": { - "X": -7.0078, - "Y": 4.1621, - "Z": 2.6845 - }, - "38": { - "X": -1.4082, - "Y": 4.1621, - "Z": 2.6845 - }, - "57": { - "X": -4.2168, - "Y": 4.2129, - "Z": 5.2706 - } - } - }, - { - "TemplateId": [ - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 209, - 210 - ], - "AttachPointId": { - "1": { - "X": -4.2597, - "Y": -3.1738, - "Z": 0.7177 - }, - "36": { - "X": -4.2070, - "Y": 4.082, - "Z": 2.5995 - }, - "37": { - "X": -7.0078, - "Y": 4.1621, - "Z": 2.6845 - }, - "38": { - "X": -1.4082, - "Y": 4.1621, - "Z": 2.6845 - }, - "41": { - "X": 0, - "Y": -2.8, - "Z": 8.5 - }, - "42": { - "X": 4.2, - "Y": 4.2, - "Z": 9 - }, - "57": { - "X": -4.2168, - "Y": 4.2129, - "Z": 5.2706 - } - } - }, - { - "TemplateId": [ - 211, - 212, - 213, - 214, - 215, - 216, - 217, - 218, - 219 - ], - "AttachPointId": { - "1": { - "X": 7.5632, - "Y": -2, - "Z": 1 - }, - "36": { - "X": -5.59, - "Y": 8.3085, - "Z": 2.5995 - }, - "37": { - "X": 1.40, - "Y": 8.244, - "Z": 2.5995 - }, - "38": { - "X": 4.1914, - "Y": 8.244, - "Z": 2.5995 - }, - "39": { - "X": -8.2597, - "Y": 2.7968, - "Z": 2.5995 - }, - "40": { - "X": -8.2597, - "Y": -2.8027, - "Z": 2.5995 - }, - "57": { - "X": -5.59, - "Y": 8.7, - "Z": 5.2706 - } - } - }, - { - "TemplateId": [ - 220, - 221, - 222, - 223, - 224, - 225, - 226, - 227, - 228 - ], - "AttachPointId": { - "1": { - "X": 7.2211, - "Y": -2.1738, - "Z": 1 - }, - "36": { - "X": -4.3270, - "Y": 0, - "Z": 2.5995 - }, - "37": { - "X": -7.12, - "Y": 0, - "Z": 2.5995 - }, - "38": { - "X": -1.5, - "Y": 0, - "Z": 2.5995 - }, - "57": { - "X": -4.3270, - "Y": 0, - "Z": 5.2706 - } - } - }, - { - "TemplateId": [ - 229, - 230, - 231, - 232, - 233, - 234, - 235, - 236, - 237, - 238, - 239, - 240, - 241, - 242, - 243, - 244, - 245, - 246 - ], - "AttachPointId": { - "1": { - "X": 7.5, - "Y": -2.1, - "Z": 1 - }, - "36": { - "X": -4.2168, - "Y": -0.125, - "Z": 2.8 - }, - "37": { - "X": 4.2168, - "Y": 8.548, - "Z": 2 - }, - "38": { - "X": -8.3047, - "Y": -2.7988, - "Z": 1.8 - }, - "39": { - "X": -8.3047, - "Y": -5.6035, - "Z": 1.8 - }, - "57": { - "X": -4.2168, - "Y": 0, - "Z": 5.2706 - } - } - }, - { - "TemplateId": [ - 247, - 248, - 249, - 250, - 251, - 252 - ], - "AttachPointId": { - "1": { - "X": 7.2632, - "Y": -2, - "Z": 1 - }, - "36": { - "X": -5.59, - "Y": 8.3085, - "Z": 2.5995 - }, - "37": { - "X": 1.40, - "Y": 8.244, - "Z": 2.5995 - }, - "38": { - "X": 4.1914, - "Y": 8.244, - "Z": 2.5995 - }, - "39": { - "X": -8.2597, - "Y": 2.7968, - "Z": 2.5995 - }, - "40": { - "X": -8.2597, - "Y": -2.8027, - "Z": 2.5995 - }, - "41": { - "X": 1.3964, - "Y": 8.2558, - "Z": 8 - }, - "42": { - "X": -1.4023, - "Y": 8.2558, - "Z": 8 - }, - "43": { - "X": -8.2597, - "Y": 2.7968, - "Z": 8 - }, - "44": { - "X": -8.2597, - "Y": -2.8027, - "Z": 8 - }, - "57": { - "X": -5.59, - "Y": 8.7, - "Z": 5.2706 - } - } - }, - { - "TemplateId": [ - 253, - 254, - 255, - 256, - 257, - 258, - 259, - 260, - 261, - 262, - 263, - 264, - 265 - ], - "AttachPointId": { - "1": { - "X": 7.2632, - "Y": -2, - "Z": 1 - }, - "36": { - "X": -5.59, - "Y": 8.3085, - "Z": 2.5995 - }, - "37": { - "X": 1.40, - "Y": 8.244, - "Z": 2.5995 - }, - "38": { - "X": 4.1914, - "Y": 8.244, - "Z": 2.5995 - }, - "39": { - "X": -8.2597, - "Y": 2.7968, - "Z": 2.5995 - }, - "40": { - "X": -8.2597, - "Y": -2.8027, - "Z": 2.5995 - }, - "41": { - "X": -4.19, - "Y": 0, - "Z": 8 - }, - "42": { - "X": 4.2128, - "Y": 8.25, - "Z": 8.7 - }, - "43": { - "X": -8.2441, - "Y": -2.8, - "Z": 8 - }, - "44": { - "X": -8.2441, - "Y": -5.6, - "Z": 8 - }, - "57": { - "X": -5.59, - "Y": 8.7, - "Z": 5.2706 - } - } - }, - { - "TemplateId": [ - 267 - ], - "AttachPointId": { - "57": { - "X": -0.4472, - "Y": 0.1484, - "Z": 0.2025 - } - } - }, - { - "TemplateId": [ - 270 - ], - "AttachPointId": { - "1": { - "X": -3.25, - "Y": -2.5156, - "Z": 8 - }, - "24": { - "X": -5.1289, - "Y": 6.6582, - "Z": 1.2 - }, - "25": { - "X": -2.2753, - "Y": 0, - "Z": 3.2 - }, - "36": { - "X": 0, - "Y": 4.3566, - "Z": 8 - }, - "37": { - "X": -2.8, - "Y": 4, - "Z": 9 - }, - "38": { - "X": 2.8, - "Y": 4, - "Z": 9 - }, - "57": { - "X": 0, - "Y": 4.3566, - "Z": 8 - } - } - }, - { - "TemplateId": [ - 275, - 276, - 277 - ], - "AttachPointId": { - "57": { - "X": 0, - "Y": -7.1191, - "Z": 2.3314 - } - } - }, - { - "TemplateId": [ - 278 - ], - "AttachPointId": { - "9": { - "X": 0, - "Y": 0, - "Z": 3.5 - }, - "10": { - "X": 0, - "Y": 10.03, - "Z": 4.019 - }, - "11": { - "X": 6.69276, - "Y": 6.9308, - "Z": 3.374, - "Yaw": 135 - }, - "12": { - "X": 6.9263, - "Y": -6.9269, - "Z": 3.374, - "Yaw": 45 - }, - "13": { - "X": 0.002039, - "Y": -9.8473, - "Z": 3.374 - }, - "14": { - "X": -6.9444, - "Y": -6.9391, - "Z": 3.374, - "Yaw": -45 - }, - "15": { - "X": -6.943, - "Y": 6.9386, - "Z": 3.374, - "Yaw": -135 - }, - "16": { - "X": -0.013981, - "Y": 3.305, - "Z": 3.374 - }, - "17": { - "X": -0.013981, - "Y": -2.9901, - "Z": 3.374, - "Yaw": 180 - }, - "24": { - "X": -11.448, - "Y": 0.000151, - "Z": -1.7376, - "Yaw": 90 - }, - "25": { - "X": 11.451, - "Y": 0, - "Z": -1.7928, - "Yaw": -90 - }, - "57": { - "X": 9.8933, - "Y": 4.1, - "Z": 5.6, - "Yaw": -70 - } - } - }, - { - "TemplateId": [ - 282 - ], - "AttachPointId": { - "57": { - "X": 0.0195, - "Y": 0.3652, - "Z": 2.3754 - } - } - }, - { - "TemplateId": [ - 598, - 599, - 600, // cherry tree house - 601, - 602, - 603 - ], - "AttachPointId": { - "57": { - "X": 3.314, - "Y": 1.964, - "Z": 1.9226, - "Yaw": 0 - }, - "10": { // + - "X": -3.95366, - "Y": -2.58823, - "Z": -3.76829, - "Yaw": 40.5138 // ? - }, - "11": { // + - "X": -3.9482, - "Y": 1.2814, - "Z": -2.98468, - "Yaw": 40.5138 // ? - }, - "12": { // + - "X": -2.30355, - "Y": 3.21458, - "Z": -2.98468, - "Yaw": 0 // ? - }, - "50": { // + - "X": -0.465947, - "Y": -3.93754, - "Z": -4.5495, - "Yaw": 0 // ? - }, - "13": { // + - "X": 2.53535, - "Y": 1.42528, - "Z": 23.4781, - "Yaw": 0 - }, - "14": { // + - "X": -9.70422, - "Y": 1.4497, - "Z": 18.1999, - "Yaw": 0 - }, - "15": { // + - "X": 3.53109, - "Y": 8.62451, - "Z": 17.2856, - "Yaw": 0 - }, - "16": { // + - "X": -9.81609, - "Y": -2.11864, - "Z": 8.3211, - "Yaw": 0 - }, - "17": { // + - "X": -0.348662, - "Y": 0.154501, - "Z": 5.62335, - "Yaw": 0 - }, - "46": { // + - "X": -3.0335, - "Y": -0.366349, - "Z": 10.3761, - "Yaw": 40.5138 // ? - }, - "48": { // + - "X": -0.337353, - "Y": 4.26788, - "Z": 17.5684, - "Yaw": 0 - }, - "49": { // + - "X": -4.31195, - "Y": 2.57559, - "Z": -5.57065, - "Yaw": 40.5138 // ? - }, - "51": { // + - "X": 1.89231, - "Y": 2.44653, - "Z": 27.7494, - "Yaw": 0 - }, - "54": { - "X": 8.786, - "Y": 7.674, - "Z": 8400.194, - "Yaw": 0 - }, - "55": { // + - "X": -5.18845, - "Y": 5.32806, - "Z": 16.1129, - "Yaw": 0 - }, - "56": { - "X": 2.582, - "Y": 0.038, - "Z": 24.3864, - "Roll": -5.3285, - "Pitch": 1.9423, - "Yaw": 56.888 - } - } - }, - { - "TemplateId": [ - 432, - 433, - 434 // cozy farmhouse - ], - "AttachPointId": { - "57": { - "X": 3.186, - "Y": 1.792, - "Z": 4205.623, - "Yaw": -40.5138 - }, - "36": { - "X": 6.124, - "Y": 5.232, - "Z": 8391.406, - "Yaw": 0 - }, - "37": { - "X": 3.072, - "Y": 4.052, - "Z": 4203.858, - "Yaw": -40.5138 - }, - "38": { - "X": 1.42, - "Y": 5.602, - "Z": 7.944, - "Yaw": 0 - }, - "39": { - "X": 2.114, - "Y": 5.602, - "Z": 8399.944, - "Yaw": 0 - }, - "40": { - "X": 5.642, - "Y": 4.896, - "Z": 12588.77, - "Yaw": 40.5138 - }, - "41": { - "X": 5.662, - "Y": 0.914, - "Z": 0.5891, - "Roll": -9.5053, - "Pitch": 9.5053, - "Yaw": -39.3851 - }, - "42": { - "X": 3.45, - "Y": 1.088, - "Z": 4196.715, - "Yaw": 40.5138 - }, - "43": { - "X": 3.45, - "Y": 4.012, - "Z": 4196.715, - "Yaw": 40.5138 - }, - "45": { - "X": 5.376, - "Y": 0.068, - "Z": 8392.759, - "Yaw": -40.5138 - }, - "1": { - "X": 2.808, - "Y": 3.272, - "Z": 12593.98, - "Yaw": 0 - }, - "9": { - "X": 4.024, - "Y": 4.116, - "Z": 8392.715, - "Yaw": -40.5138 - }, - "10": { - "X": 3.094, - "Y": 5.6, - "Z": 1.4565, - "Yaw": 0 - }, - "11": { - "X": 4.902, - "Y": 2.704, - "Z": 10.9722, - "Roll": 0, - "Pitch": 10.4679, - "Yaw": 0 - }, - "12": { - "X": 4.922, - "Y": 2.33, - "Z": 4206.888, - "Roll": 0, - "Pitch": 9.5798, - "Yaw": 0 - }, - "13": { - "X": 5.504, - "Y": 3.31, - "Z": 12588.75, - "Roll": 0, - "Pitch": 0, - "Yaw": 40.5138 - } - } + { + "TemplateId": [ + 9900005, + 283, + 89, + 267, + 277, + 276, + 275, + 282, + 9900004, + 9900002, + 9900003 + ], + "AttachPointId": { + "57": { + "X": 0.0, + "Y": 0.0, + "Z": 2.3314, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + } } -] + }, + { + "TemplateId": [ + 433, + 403, + 432, + 402, + 418, + 417 + ], + "AttachPointId": { + "57": { + "X": 3.181641, + "Y": -1.785156, + "Z": 9.6233, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "36": { + "X": -6.121094, + "Y": 5.226563, + "Z": -0.5928, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": 3.070313, + "Y": -4.050781, + "Z": 7.8586, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "38": { + "X": 1.410156, + "Y": 5.599609, + "Z": 7.9446, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "39": { + "X": -2.111328, + "Y": 5.599609, + "Z": 7.9446, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "40": { + "X": -5.638672, + "Y": -4.886719, + "Z": 0.7727, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "41": { + "X": 5.658203, + "Y": 0.9042969, + "Z": 0.5897, + "Roll": -27.1329, + "Pitch": 0.0003444933, + "Yaw": -89.99857 + }, + "42": { + "X": 3.439453, + "Y": -1.085938, + "Z": 0.7157, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "43": { + "X": 3.439453, + "Y": -4.011719, + "Z": 0.7157, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "44": { + "X": -2.447266, + "Y": -4.019531, + "Z": 0.7157, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "45": { + "X": -5.367188, + "Y": 0.06640625, + "Z": 0.7597, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "1": { + "X": -2.800781, + "Y": -3.265625, + "Z": 5.9798, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": -4.023438, + "Y": 4.113281, + "Z": 0.7157, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "10": { + "X": 3.091797, + "Y": 5.597656, + "Z": 1.457, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "11": { + "X": 4.892578, + "Y": 2.699219, + "Z": 10.9729, + "Roll": 0.0, + "Pitch": 21.05936, + "Yaw": 0.0 + }, + "12": { + "X": 4.912109, + "Y": -2.322266, + "Z": 10.8888, + "Roll": 0.0, + "Pitch": 19.25139, + "Yaw": 0.0 + }, + "13": { + "X": -5.503906, + "Y": -3.302734, + "Z": 0.7537, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + } + } + }, + { + "TemplateId": [ + 397, + 396, + 395 + ], + "AttachPointId": { + "57": { + "X": 0.4257813, + "Y": -6.601563, + "Z": 4.4032, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "24": { + "X": 0.0, + "Y": -3.074219, + "Z": -5.5558, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 422, + 407 + ], + "AttachPointId": { + "57": { + "X": -4.216797, + "Y": 4.212891, + "Z": 6.27, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -4.207031, + "Y": 4.082031, + "Z": 3.5989, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -7.007813, + "Y": 4.162109, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": -1.408203, + "Y": 4.162109, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -4.259766, + "Y": -3.173828, + "Z": 1.7181, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": 1.867188, + "Y": -2.736328, + "Z": 7.8446, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -6.230469, + "Y": 6.964844, + "Z": 2.9586, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + }, + "11": { + "X": 4.898438, + "Y": 0.2265625, + "Z": 7.8486, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "12": { + "X": -9.892578, + "Y": 4.558594, + "Z": 1.6191, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "45": { + "X": 10.22656, + "Y": 3.744141, + "Z": -0.2567, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + } + } + }, + { + "TemplateId": [ + 175, + 172, + 319 + ], + "AttachPointId": { + "36": { + "X": -0.0078125, + "Y": 4.097656, + "Z": 2.5995, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -2.808594, + "Y": 4.134766, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "57": { + "X": 0.0, + "Y": 4.208984, + "Z": 5.2175, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": 2.789063, + "Y": 4.134766, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -3.097656, + "Y": -1.912109, + "Z": 0.7197, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "24": { + "X": 0.0, + "Y": 7.003906, + "Z": -3.7261, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 9900006, + 9900007 + ], + "AttachPointId": { + "57": { + "X": -1.056641, + "Y": 13.41406, + "Z": 1.6051, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -68.10518 + }, + "36": { + "X": -5.333984, + "Y": 7.041016, + "Z": 0.2925, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 139.0206 + }, + "40": { + "X": 1.519531, + "Y": -5.308594, + "Z": 0.2655, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "41": { + "X": -1.224609, + "Y": -5.382813, + "Z": 0.2655, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "60": { + "X": -2.957031, + "Y": -7.068359, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "61": { + "X": -2.966797, + "Y": -5.003906, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "62": { + "X": -4.888672, + "Y": -3.054688, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -10.29883, + "Y": 0.1835938, + "Z": 0.2815, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": -3.326172, + "Y": 8.925781, + "Z": 0.2815, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + }, + "10": { + "X": 1.433594, + "Y": 13.49414, + "Z": 1.39, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "11": { + "X": 3.033203, + "Y": -3.181641, + "Z": 0.2655, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "12": { + "X": -3.025391, + "Y": -3.181641, + "Z": 0.2655, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "63": { + "X": -7.074219, + "Y": -3.044922, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "64": { + "X": 3.236328, + "Y": -7.068359, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "65": { + "X": 3.226563, + "Y": -5.003906, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "66": { + "X": 5.117188, + "Y": -3.054688, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "67": { + "X": 7.335938, + "Y": -3.054688, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "68": { + "X": 0.1894531, + "Y": 12.6875, + "Z": 0.5206, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "69": { + "X": 7.287109, + "Y": 3.878906, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "70": { + "X": 5.136719, + "Y": 3.878906, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "71": { + "X": 3.226563, + "Y": 5.878906, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "72": { + "X": 3.226563, + "Y": 7.972656, + "Z": 0.3406, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 171 + ], + "AttachPointId": { + "57": { + "X": 0.0, + "Y": 4.208984, + "Z": 5.2175, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -0.0078125, + "Y": 4.097656, + "Z": 2.5995, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": 2.789063, + "Y": 4.134766, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -2.808594, + "Y": 4.134766, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -3.097656, + "Y": -1.912109, + "Z": 0.7197, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": 3.398438, + "Y": 5.861328, + "Z": 1.0128, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "39": { + "X": -2.111328, + "Y": 5.599609, + "Z": 7.9446, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "40": { + "X": -5.638672, + "Y": -4.886719, + "Z": 0.7727, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "41": { + "X": 5.658203, + "Y": 0.9042969, + "Z": 0.5897, + "Roll": -27.1329, + "Pitch": 0.0003444933, + "Yaw": -89.99857 + }, + "42": { + "X": 3.439453, + "Y": -1.085938, + "Z": 0.7157, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "43": { + "X": 3.439453, + "Y": -4.011719, + "Z": 0.7157, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "44": { + "X": -2.447266, + "Y": -4.019531, + "Z": 0.7157, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "45": { + "X": -5.367188, + "Y": 0.06640625, + "Z": 0.7597, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "10": { + "X": 3.091797, + "Y": 5.597656, + "Z": 1.457, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "11": { + "X": 4.892578, + "Y": 2.699219, + "Z": 10.9729, + "Roll": 0.0, + "Pitch": 21.05936, + "Yaw": 0.0 + }, + "12": { + "X": 4.912109, + "Y": -2.322266, + "Z": 10.8888, + "Roll": 0.0, + "Pitch": 19.25139, + "Yaw": 0.0 + }, + "13": { + "X": -5.503906, + "Y": -3.302734, + "Z": 0.7537, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + } + } + }, + { + "TemplateId": [ + 434, + 419, + 404 + ], + "AttachPointId": { + "57": { + "X": 3.181641, + "Y": -1.785156, + "Z": 9.6233, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "36": { + "X": -6.121094, + "Y": 5.226563, + "Z": -0.5928, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": 3.070313, + "Y": -4.050781, + "Z": 7.8586, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "38": { + "X": 1.410156, + "Y": 5.599609, + "Z": 7.9446, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "39": { + "X": -2.111328, + "Y": 5.599609, + "Z": 7.9446, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "40": { + "X": -5.638672, + "Y": -4.886719, + "Z": 0.7727, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "41": { + "X": 5.658203, + "Y": 0.9042969, + "Z": 0.5897, + "Roll": -27.1329, + "Pitch": 0.0003444933, + "Yaw": -89.99857 + }, + "42": { + "X": 3.439453, + "Y": -1.085938, + "Z": 0.7157, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "43": { + "X": 3.439453, + "Y": -4.011719, + "Z": 0.7157, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "45": { + "X": -5.367188, + "Y": 0.06640625, + "Z": 0.7597, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "1": { + "X": -2.800781, + "Y": -3.265625, + "Z": 5.9798, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": -4.023438, + "Y": 4.113281, + "Z": 0.7157, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "10": { + "X": 3.091797, + "Y": 5.597656, + "Z": 1.457, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "11": { + "X": 4.892578, + "Y": 2.699219, + "Z": 10.9729, + "Roll": 0.0, + "Pitch": 21.05936, + "Yaw": 0.0 + }, + "12": { + "X": 4.912109, + "Y": -2.322266, + "Z": 10.8888, + "Roll": 0.0, + "Pitch": 19.25139, + "Yaw": 0.0 + }, + "13": { + "X": -5.503906, + "Y": -3.302734, + "Z": 0.7537, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + } + } + }, + { + "TemplateId": [ + 600, + 599, + 598 + ], + "AttachPointId": { + "57": { + "X": 3.306641, + "Y": 1.953125, + "Z": 1.9232, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -3.228516, + "Y": -2.921875, + "Z": 18.2008, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "11": { + "X": -3.224609, + "Y": 0.9453125, + "Z": 18.9841, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "12": { + "X": -1.578125, + "Y": 2.878906, + "Z": 18.9841, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "50": { + "X": 0.2558594, + "Y": -4.271484, + "Z": 17.4195, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "13": { + "X": 2.535156, + "Y": 1.423828, + "Z": 23.4779, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "14": { + "X": -9.703125, + "Y": 1.449219, + "Z": 18.1998, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "15": { + "X": 3.529297, + "Y": 8.623047, + "Z": 17.2854, + "Roll": -0.1014178, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "16": { + "X": -9.814453, + "Y": -2.117188, + "Z": 8.3208, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "17": { + "X": -0.3476563, + "Y": 0.1542969, + "Z": 5.6237, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "46": { + "X": -3.033203, + "Y": -0.3652344, + "Z": 10.3756, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "48": { + "X": -0.3359375, + "Y": 4.267578, + "Z": 17.5685, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "49": { + "X": -3.587891, + "Y": 2.240234, + "Z": 16.398, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "51": { + "X": 1.890625, + "Y": 2.445313, + "Z": 27.7496, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "54": { + "X": -8.779297, + "Y": 7.669922, + "Z": 8.1947, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "55": { + "X": -5.1875, + "Y": 5.328125, + "Z": 16.1129, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "56": { + "X": 2.580078, + "Y": 0.03710938, + "Z": 24.3873, + "Roll": 3.207269, + "Pitch": 10.90084, + "Yaw": 172.6266 + } + } + }, + { + "TemplateId": [ + 669, + 677 + ], + "AttachPointId": { + "57": { + "X": 0.02734375, + "Y": 4.605469, + "Z": 11.5981, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": 0.0234375, + "Y": -3.263672, + "Z": 7.2163, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -0.00390625, + "Y": 4.105469, + "Z": 9.0941, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -2.804688, + "Y": 4.068359, + "Z": 9.2792, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": 2.794922, + "Y": 4.068359, + "Z": 9.2792, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "24": { + "X": 5.199219, + "Y": -2.210938, + "Z": -3.433, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "39": { + "X": 1.728516, + "Y": 1.714844, + "Z": 0.2735, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "40": { + "X": -1.5625, + "Y": 1.708984, + "Z": 0.2735, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + } + } + }, + { + "TemplateId": [ + 436, + 406, + 421, + 420 + ], + "AttachPointId": { + "57": { + "X": -4.216797, + "Y": 4.212891, + "Z": 6.27, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -4.207031, + "Y": 4.082031, + "Z": 3.5989, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -7.007813, + "Y": 4.162109, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": -1.408203, + "Y": 4.162109, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -4.259766, + "Y": -3.173828, + "Z": 1.7181, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": 1.867188, + "Y": -2.804688, + "Z": 7.8446, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -6.230469, + "Y": 6.964844, + "Z": 2.9586, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + }, + "11": { + "X": 4.898438, + "Y": 0.15625, + "Z": 7.8486, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "12": { + "X": -9.892578, + "Y": 4.558594, + "Z": 1.6191, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + } + } + }, + { + "TemplateId": [ + 181, + 315 + ], + "AttachPointId": { + "57": { + "X": 0.02734375, + "Y": 4.605469, + "Z": 5.2055, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -0.00390625, + "Y": 4.105469, + "Z": 2.7005, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -2.804688, + "Y": 4.068359, + "Z": 2.8866, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": 2.794922, + "Y": 4.068359, + "Z": 2.8866, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -0.05273438, + "Y": -3.146484, + "Z": 0.8228, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "24": { + "X": 0.0, + "Y": 8.28125, + "Z": -4.7455, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 465, + 478 + ], + "AttachPointId": { + "57": { + "X": -4.207031, + "Y": 0.00390625, + "Z": 6.27, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -4.197266, + "Y": -0.02734375, + "Z": 3.5989, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": 4.199219, + "Y": 8.351563, + "Z": 4.2271, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": -8.412109, + "Y": -2.798828, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "39": { + "X": -8.412109, + "Y": -5.599609, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "1": { + "X": 7.419922, + "Y": -2.117188, + "Z": 1.8462, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": 1.837891, + "Y": 1.435547, + "Z": 7.8926, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -6.287109, + "Y": 10.60352, + "Z": 2.9576, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + }, + "11": { + "X": 4.867188, + "Y": 4.400391, + "Z": 7.8966, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "12": { + "X": -9.871094, + "Y": 7.972656, + "Z": 1.6521, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + } + } + }, + { + "TemplateId": [ + 424, + 408, + 438 + ], + "AttachPointId": { + "57": { + "X": -4.216797, + "Y": 4.212891, + "Z": 6.27, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -4.207031, + "Y": 4.082031, + "Z": 3.5989, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -7.007813, + "Y": 4.162109, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": -1.408203, + "Y": 4.162109, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "41": { + "X": 0.1132813, + "Y": -2.806641, + "Z": 8.9991, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "42": { + "X": 4.208984, + "Y": 4.152344, + "Z": 9.6273, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -4.304688, + "Y": -3.154297, + "Z": 1.7211, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": 1.857422, + "Y": -2.8125, + "Z": 13.2618, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -6.230469, + "Y": 6.964844, + "Z": 2.9586, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + }, + "11": { + "X": 4.886719, + "Y": 0.1484375, + "Z": 13.2658, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "12": { + "X": -9.873047, + "Y": 4.441406, + "Z": 1.6171, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + } + } + }, + { + "TemplateId": [ + 173, + 179, + 178, + 174, + 520, + 322 + ], + "AttachPointId": { + "36": { + "X": -0.0078125, + "Y": 4.097656, + "Z": 2.5995, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -2.808594, + "Y": 4.134766, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": 2.789063, + "Y": 4.134766, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "57": { + "X": 0.0, + "Y": 4.208984, + "Z": 5.2175, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -3.097656, + "Y": -1.912109, + "Z": 0.7197, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "24": { + "X": 0.0, + "Y": 7.003906, + "Z": -3.7261, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 469, + 450, + 468, + 481, + 474 + ], + "AttachPointId": { + "57": { + "X": -5.607422, + "Y": 8.404297, + "Z": 6.27, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -5.597656, + "Y": 8.265625, + "Z": 3.5989, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": 1.398438, + "Y": 8.351563, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": 4.199219, + "Y": 8.351563, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "39": { + "X": -8.369141, + "Y": 2.798828, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "40": { + "X": -8.369141, + "Y": -2.798828, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "41": { + "X": -4.197266, + "Y": -0.04101563, + "Z": 8.938, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "42": { + "X": 4.199219, + "Y": 8.349609, + "Z": 9.5663, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "43": { + "X": -8.349609, + "Y": -2.798828, + "Z": 9.0241, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "44": { + "X": -8.349609, + "Y": -5.599609, + "Z": 9.0241, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "1": { + "X": 7.351563, + "Y": -1.988281, + "Z": 1.8462, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": 1.869141, + "Y": 1.435547, + "Z": 13.1517, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -6.287109, + "Y": 10.60352, + "Z": 2.9576, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + }, + "11": { + "X": 4.898438, + "Y": 4.400391, + "Z": 13.1557, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "12": { + "X": -9.943359, + "Y": 7.533203, + "Z": 1.6071, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + } + } + }, + { + "TemplateId": [ + 602 + ], + "AttachPointId": { + "57": { + "X": 3.306641, + "Y": 1.953125, + "Z": 1.9232, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -3.224609, + "Y": -2.921875, + "Z": 18.2008, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "11": { + "X": -3.21875, + "Y": 0.9453125, + "Z": 18.9841, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "12": { + "X": -1.574219, + "Y": 2.878906, + "Z": 18.9841, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "13": { + "X": 2.535156, + "Y": 1.423828, + "Z": 23.4779, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "14": { + "X": -9.703125, + "Y": 1.449219, + "Z": 18.1998, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "15": { + "X": 3.529297, + "Y": 8.623047, + "Z": 17.2854, + "Roll": -0.1014178, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "16": { + "X": -9.814453, + "Y": -2.117188, + "Z": 8.3208, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "17": { + "X": -0.3476563, + "Y": 0.1542969, + "Z": 5.6237, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "46": { + "X": -3.033203, + "Y": -0.3652344, + "Z": 10.3756, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "48": { + "X": -0.3359375, + "Y": 4.267578, + "Z": 17.5685, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "49": { + "X": -3.582031, + "Y": 2.240234, + "Z": 16.398, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "51": { + "X": 1.890625, + "Y": 2.445313, + "Z": 27.7496, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "54": { + "X": -8.779297, + "Y": 7.669922, + "Z": 8.1947, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "55": { + "X": -5.1875, + "Y": 5.328125, + "Z": 16.1129, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "56": { + "X": 2.580078, + "Y": 0.03710938, + "Z": 24.3873, + "Roll": 3.207269, + "Pitch": 10.90084, + "Yaw": 172.6266 + }, + "50": { + "X": 0.2617188, + "Y": -4.271484, + "Z": 17.4195, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 464, + 482 + ], + "AttachPointId": { + "57": { + "X": -5.607422, + "Y": 8.404297, + "Z": 6.27, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -5.597656, + "Y": 8.265625, + "Z": 3.5989, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": 1.398438, + "Y": 8.351563, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": 4.199219, + "Y": 8.351563, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "39": { + "X": -8.369141, + "Y": 2.798828, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "40": { + "X": -8.369141, + "Y": -2.798828, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "41": { + "X": -4.197266, + "Y": -0.04101563, + "Z": 8.938, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "42": { + "X": 4.199219, + "Y": 8.349609, + "Z": 9.5663, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "43": { + "X": -8.349609, + "Y": -2.798828, + "Z": 9.0241, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "44": { + "X": -8.349609, + "Y": -5.599609, + "Z": 9.0241, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "1": { + "X": 7.351563, + "Y": -1.988281, + "Z": 1.8462, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": 1.859375, + "Y": 1.443359, + "Z": 13.2468, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -6.287109, + "Y": 10.60352, + "Z": 2.9576, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + }, + "11": { + "X": 4.888672, + "Y": 4.40625, + "Z": 13.2508, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "12": { + "X": -9.943359, + "Y": 7.533203, + "Z": 1.6071, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "45": { + "X": 10.13867, + "Y": 7.949219, + "Z": -0.2097, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + } + } + }, + { + "TemplateId": [ + 679, + 678, + 673, + 674 + ], + "AttachPointId": { + "36": { + "X": -0.9316406, + "Y": 2.943359, + "Z": 8.951, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -3.732422, + "Y": 2.980469, + "Z": 9.0361, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "57": { + "X": -0.9238281, + "Y": 3.054688, + "Z": 11.5691, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": 1.865234, + "Y": 2.980469, + "Z": 9.0361, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -4.021484, + "Y": -3.066406, + "Z": 7.0713, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "39": { + "X": 0.7890625, + "Y": 0.515625, + "Z": 0.4326, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "40": { + "X": -2.501953, + "Y": 0.5097656, + "Z": 0.4326, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + } + } + }, + { + "TemplateId": [ + 410, + 440 + ], + "AttachPointId": { + "57": { + "X": -4.216797, + "Y": 4.212891, + "Z": 6.27, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -4.207031, + "Y": 4.082031, + "Z": 3.5989, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -7.007813, + "Y": 4.162109, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": -1.408203, + "Y": 4.162109, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "41": { + "X": 0.1132813, + "Y": -2.806641, + "Z": 8.9991, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "42": { + "X": 4.208984, + "Y": 4.152344, + "Z": 9.6273, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -4.304688, + "Y": -3.154297, + "Z": 1.7211, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": 1.857422, + "Y": -2.8125, + "Z": 13.2618, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -6.230469, + "Y": 6.964844, + "Z": 2.9586, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + }, + "11": { + "X": 4.886719, + "Y": 0.1484375, + "Z": 13.2658, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "12": { + "X": -9.873047, + "Y": 4.441406, + "Z": 1.6171, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "45": { + "X": 10.22656, + "Y": 3.744141, + "Z": -0.2567, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + } + } + }, + { + "TemplateId": [ + 618, + 604, + 605 + ], + "AttachPointId": { + "57": { + "X": 9.589844, + "Y": 3.994141, + "Z": 5.7297, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -69.99838 + }, + "25": { + "X": 11.44922, + "Y": 0.0, + "Z": -3.2929, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "24": { + "X": -11.44727, + "Y": 0.0, + "Z": -3.2379, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "9": { + "X": 0.0, + "Y": 0.0, + "Z": 2.5194, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": 0.0, + "Y": 10.0293, + "Z": 2.5194, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "11": { + "X": -5.982422, + "Y": -5.960938, + "Z": 1.8742, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -44.99853 + }, + "12": { + "X": -6.941406, + "Y": 6.9375, + "Z": 1.8742, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -135.0022 + }, + "13": { + "X": 4.025391, + "Y": 7.767578, + "Z": 9.4692, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -29.19799 + }, + "14": { + "X": 8.027344, + "Y": 3.867188, + "Z": 9.4692, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -65.60352 + }, + "15": { + "X": 8.566406, + "Y": -2.322266, + "Z": 9.4692, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -104.9035 + }, + "16": { + "X": -2.8125, + "Y": 8.291016, + "Z": 9.4692, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 19.25848 + }, + "17": { + "X": -9.001953, + "Y": -1.822266, + "Z": 9.4692, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 102.7771 + } + } + }, + { + "TemplateId": [ + 202 + ], + "AttachPointId": { + "57": { + "X": -4.216797, + "Y": 4.212891, + "Z": 5.2706, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -4.207031, + "Y": 4.082031, + "Z": 2.5995, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -7.007813, + "Y": 4.162109, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": -1.408203, + "Y": 4.162109, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "41": { + "X": 0.1132813, + "Y": -2.806641, + "Z": 7.9987, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "42": { + "X": 4.208984, + "Y": 4.152344, + "Z": 8.6279, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -4.304688, + "Y": -3.154297, + "Z": 0.7217, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 742 + ], + "AttachPointId": { + "1": { + "X": 5.623047, + "Y": -6.757813, + "Z": 47.2895, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -30.001 + }, + "38": { + "X": -7.351563, + "Y": -9.503906, + "Z": 42.3765, + "Roll": 23.07241, + "Pitch": -2.863728, + "Yaw": -7.447351 + }, + "39": { + "X": -5.818359, + "Y": 8.617188, + "Z": 50.959, + "Roll": 0.0, + "Pitch": 22.9797, + "Yaw": 0.0 + }, + "43": { + "X": -4.335938, + "Y": -8.664063, + "Z": 43.8081, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -2.000479 + }, + "41": { + "X": 6.957031, + "Y": -2.292969, + "Z": 57.9769, + "Roll": -8.40188, + "Pitch": -21.71251, + "Yaw": 1.992517 + }, + "57": { + "X": -3.287109, + "Y": -5.607422, + "Z": 3.7269, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 58.90663 + }, + "13": { + "X": 3.447266, + "Y": -5.128906, + "Z": 55.813, + "Roll": 18.19916, + "Pitch": -3.807381, + "Yaw": -50.56976 + }, + "37": { + "X": -9.554688, + "Y": -0.7324219, + "Z": 34.1932, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.4819 + }, + "36": { + "X": -4.138672, + "Y": 1.917969, + "Z": 2.8866, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 2.409723 + }, + "10": { + "X": -9.113281, + "Y": -5.435547, + "Z": 2.6435, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "40": { + "X": -13.89453, + "Y": -1.035156, + "Z": 2.8466, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "45": { + "X": 2.896484, + "Y": 0.2988281, + "Z": 46.6363, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 59.54219 + }, + "9": { + "X": 2.548828, + "Y": -2.611328, + "Z": 48.9052, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "12": { + "X": 0.4453125, + "Y": 7.71875, + "Z": 42.1635, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -9.628526 + }, + "14": { + "X": 13.31055, + "Y": 6.417969, + "Z": 48.2709, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "11": { + "X": 1.673828, + "Y": -9.927734, + "Z": 47.5006, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "42": { + "X": -2.941406, + "Y": -7.4375, + "Z": 48.0759, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -2.000479 + }, + "15": { + "X": 6.929688, + "Y": 7.824219, + "Z": 42.4566, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 663 + ], + "AttachPointId": { + "9": { + "X": -0.02929688, + "Y": -2.541016, + "Z": 3.887, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "11": { + "X": -1.826172, + "Y": 0.5351563, + "Z": 1.2009, + "Roll": -55.87581, + "Pitch": -0.1049362, + "Yaw": 74.16744 + }, + "48": { + "X": -0.02929688, + "Y": -1.908203, + "Z": 2.7195, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "49": { + "X": 2.21875, + "Y": 0.046875, + "Z": 14.0161, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "57": { + "X": 0.9492188, + "Y": 2.289063, + "Z": 3.5148, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -1.328125, + "Y": 1.419922, + "Z": 1.2009, + "Roll": -55.4292, + "Pitch": 0.1651531, + "Yaw": 43.77477 + }, + "12": { + "X": -1.861328, + "Y": -0.484375, + "Z": 1.2009, + "Roll": -55.87668, + "Pitch": -0.1046981, + "Yaw": 102.3524 + }, + "13": { + "X": -1.339844, + "Y": -1.386719, + "Z": 1.2009, + "Roll": -55.87908, + "Pitch": -0.103946, + "Yaw": 133.1363 + }, + "14": { + "X": -0.4921875, + "Y": -1.894531, + "Z": 1.2009, + "Roll": -55.87735, + "Pitch": -0.1005531, + "Yaw": 164.4781 + }, + "15": { + "X": 0.5234375, + "Y": -1.880859, + "Z": 1.2009, + "Roll": -55.87548, + "Pitch": -0.09980582, + "Yaw": -165.0512 + }, + "16": { + "X": 1.400391, + "Y": -1.388672, + "Z": 1.2009, + "Roll": -55.87641, + "Pitch": -0.1058756, + "Yaw": -134.6493 + }, + "17": { + "X": 1.908203, + "Y": -0.4882813, + "Z": 1.2009, + "Roll": -55.87869, + "Pitch": -0.1074174, + "Yaw": -105.682 + }, + "46": { + "X": 1.875, + "Y": 0.5292969, + "Z": 1.2009, + "Roll": -55.87525, + "Pitch": -0.1050887, + "Yaw": -76.51639 + }, + "47": { + "X": 1.355469, + "Y": 1.416016, + "Z": 1.2009, + "Roll": -55.87594, + "Pitch": -0.1056115, + "Yaw": -46.85312 + } + } + }, + { + "TemplateId": [ + 662 + ], + "AttachPointId": { + "57": { + "X": 3.306641, + "Y": 1.953125, + "Z": 1.9232, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -3.224609, + "Y": -2.921875, + "Z": 18.2008, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "11": { + "X": -3.21875, + "Y": 0.9453125, + "Z": 18.9841, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "12": { + "X": -1.574219, + "Y": 2.878906, + "Z": 18.9841, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "17": { + "X": -0.3476563, + "Y": 0.1542969, + "Z": 5.6237, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "48": { + "X": -0.3359375, + "Y": 4.267578, + "Z": 17.5685, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "49": { + "X": -3.582031, + "Y": 2.240234, + "Z": 16.398, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "51": { + "X": 1.890625, + "Y": 2.445313, + "Z": 27.7496, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "56": { + "X": 2.580078, + "Y": 0.03710938, + "Z": 24.3873, + "Roll": 3.207269, + "Pitch": 10.90084, + "Yaw": 172.6266 + }, + "50": { + "X": 0.2617188, + "Y": -4.271484, + "Z": 17.4195, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "46": { + "X": -3.033203, + "Y": -0.3652344, + "Z": 10.3756, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "13": { + "X": 2.535156, + "Y": 1.423828, + "Z": 23.4779, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "14": { + "X": -9.703125, + "Y": 1.449219, + "Z": 18.1998, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "15": { + "X": 3.529297, + "Y": 8.623047, + "Z": 17.2854, + "Roll": -0.1014178, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "16": { + "X": -9.814453, + "Y": -2.117188, + "Z": 8.3208, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 640 + ], + "AttachPointId": { + "9": { + "X": -0.02929688, + "Y": -2.541016, + "Z": 3.887, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "48": { + "X": -0.02929688, + "Y": -1.908203, + "Z": 2.7195, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "49": { + "X": 2.21875, + "Y": 0.046875, + "Z": 14.0161, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "57": { + "X": 0.9492188, + "Y": 2.289063, + "Z": 3.5148, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -1.328125, + "Y": 1.419922, + "Z": 1.2009, + "Roll": -55.4292, + "Pitch": 0.1651531, + "Yaw": 43.77477 + } + } + }, + { + "TemplateId": [ + 92, + 43, + 90, + 41, + 607, + 606, + 609, + 608, + 610 + ], + "AttachPointId": { + "1": { + "X": 0.0, + "Y": 0.0, + "Z": 0.7337, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "57": { + "X": 2.521484, + "Y": 0.3046875, + "Z": 4.0921, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 405 + ], + "AttachPointId": { + "57": { + "X": -4.216797, + "Y": 4.212891, + "Z": 6.27, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -4.207031, + "Y": 4.082031, + "Z": 3.5989, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -7.007813, + "Y": 4.162109, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": -1.408203, + "Y": 4.162109, + "Z": 3.6849, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": -4.259766, + "Y": -3.173828, + "Z": 1.7181, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "9": { + "X": 1.869141, + "Y": -2.804688, + "Z": 7.8446, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "10": { + "X": -6.230469, + "Y": 6.964844, + "Z": 2.9586, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + }, + "12": { + "X": -9.892578, + "Y": 4.558594, + "Z": 1.6191, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "11": { + "X": 4.898438, + "Y": 0.15625, + "Z": 7.8486, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + } + } + }, + { + "TemplateId": [ + 256 + ], + "AttachPointId": { + "57": { + "X": -5.607422, + "Y": 8.404297, + "Z": 5.2706, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": -5.597656, + "Y": 8.265625, + "Z": 2.5995, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": 1.398438, + "Y": 8.351563, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": 4.199219, + "Y": 8.351563, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "39": { + "X": -8.369141, + "Y": 2.798828, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "40": { + "X": -8.369141, + "Y": -2.798828, + "Z": 2.6845, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "41": { + "X": -4.197266, + "Y": -0.04101563, + "Z": 7.9376, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "42": { + "X": 4.199219, + "Y": 8.349609, + "Z": 8.5669, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "43": { + "X": -8.349609, + "Y": -2.798828, + "Z": 8.0237, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "44": { + "X": -8.349609, + "Y": -5.599609, + "Z": 8.0237, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "1": { + "X": 7.351563, + "Y": -1.988281, + "Z": 0.8458, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 681 + ], + "AttachPointId": { + "57": { + "X": 3.517578, + "Y": 3.472656, + "Z": 5.4776, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": 7.058594, + "Y": 0.4726563, + "Z": 3.6139, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": 9.822266, + "Y": -9.271484, + "Z": 3.6139, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "38": { + "X": -7.058594, + "Y": 0.4726563, + "Z": 3.6139, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "39": { + "X": -9.818359, + "Y": -9.271484, + "Z": 3.6139, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "40": { + "X": 0.0, + "Y": 3.181641, + "Z": 2.0372, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "41": { + "X": 0.0, + "Y": 3.181641, + "Z": 8.2608, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "1": { + "X": 0.078125, + "Y": -19.54102, + "Z": 3.0947, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "42": { + "X": 0.0, + "Y": 3.169922, + "Z": 14.1301, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 668 + ], + "AttachPointId": { + "57": { + "X": 4.035156, + "Y": 3.501953, + "Z": 3.3918, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": 0.3007813, + "Y": 3.357422, + "Z": 1.0318, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": -2.03125, + "Y": 3.248047, + "Z": 2.3564, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "38": { + "X": 5.458984, + "Y": 3.248047, + "Z": 2.3564, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "39": { + "X": 7.820313, + "Y": -2.384766, + "Z": 2.3564, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "41": { + "X": -6.654297, + "Y": -5.357422, + "Z": 1.458, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "42": { + "X": -5.816406, + "Y": 0.9667969, + "Z": 1.458, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -135.0022 + }, + "43": { + "X": -8.072266, + "Y": -2.460938, + "Z": 1.392, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "1": { + "X": 1.712891, + "Y": -6.958984, + "Z": 1.1459, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + }, + { + "TemplateId": [ + 285 + ], + "AttachPointId": { + "57": { + "X": 4.873047, + "Y": 6.060547, + "Z": 5.4926, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "36": { + "X": 0.0, + "Y": 7.015625, + "Z": 1.1359, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "37": { + "X": 0.001953125, + "Y": -16.4375, + "Z": 7.4995, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 180.0 + }, + "38": { + "X": -9.462891, + "Y": -4.941406, + "Z": 1.8992, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 90.00115 + }, + "39": { + "X": 9.462891, + "Y": -4.935547, + "Z": 1.9052, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -90.00115 + }, + "40": { + "X": 2.029297, + "Y": 11.83789, + "Z": 13.78, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": -42.31242 + }, + "41": { + "X": -0.015625, + "Y": 12.95508, + "Z": 13.6449, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + }, + "42": { + "X": -2.109375, + "Y": 11.92969, + "Z": 13.782, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 42.52249 + }, + "1": { + "X": -0.005859375, + "Y": -14.98242, + "Z": 1.2749, + "Roll": 0.0, + "Pitch": 0.0, + "Yaw": 0.0 + } + } + } +] \ No newline at end of file diff --git a/AAEmu.Game/GameData/SchedulesGameData.cs b/AAEmu.Game/GameData/SchedulesGameData.cs index 4c837e3eb1..7d9b26408e 100644 --- a/AAEmu.Game/GameData/SchedulesGameData.cs +++ b/AAEmu.Game/GameData/SchedulesGameData.cs @@ -20,6 +20,7 @@ public class SchedulesGameData : Singleton, IGameDataLoader private Dictionary _gameScheduleSpawners; private Dictionary _gameScheduleDoodads; private Dictionary _gameScheduleQuests; + private Dictionary _scheduleItems; public void Load(SqliteConnection connection, SqliteConnection connection2) { @@ -27,6 +28,7 @@ public void Load(SqliteConnection connection, SqliteConnection connection2) _gameScheduleSpawners = new Dictionary(); _gameScheduleDoodads = new Dictionary(); _gameScheduleQuests = new Dictionary(); + _scheduleItems = new Dictionary(); using (var command = connection.CreateCommand()) { @@ -86,6 +88,7 @@ public void Load(SqliteConnection connection, SqliteConnection connection2) } } } + using (var command = connection.CreateCommand()) { command.CommandText = "SELECT * FROM game_schedule_doodads"; @@ -104,6 +107,7 @@ public void Load(SqliteConnection connection, SqliteConnection connection2) } } } + using (var command = connection.CreateCommand()) { command.CommandText = "SELECT * FROM game_schedule_quests"; @@ -122,6 +126,56 @@ public void Load(SqliteConnection connection, SqliteConnection connection2) } } } + + using (var command = connection.CreateCommand()) + { + command.CommandText = "SELECT * FROM schedule_items"; + command.Prepare(); + using (var sqliteReader = command.ExecuteReader()) + using (var reader = new SQLiteWrapperReader(sqliteReader)) + { + while (reader.Read()) + { + var template = new ScheduleItems(); + template.Id = reader.GetUInt32("id"); + template.ActiveTake = reader.GetBoolean("active_take", true); + template.AutoTakeDelay = reader.GetUInt32("auto_take_delay"); + //template.disable_key_string = LocalizationManager.Instance.Get("disable_key_string", "disable_key_string", template.Id); + template.EdDay = reader.GetUInt32("ed_day"); + template.EdHour = reader.GetUInt32("ed_hour"); + template.EdMin = reader.GetUInt32("ed_min"); + template.EdMonth = reader.GetUInt32("ed_month"); + template.EdYear = reader.GetUInt32("ed_year"); + //template.enable_key_string = LocalizationManager.Instance.Get("enable_key_string", "enable_key_string", template.Id); + template.GiveMax = reader.GetUInt32("give_max"); + template.GiveTerm = reader.GetUInt32("give_term"); + template.GiveTerm = reader.GetUInt32("give_term"); + //template.icon_path = LocalizationManager.Instance.Get("icon_path", "icon_path", template.Id); + template.ItemCount = reader.GetUInt32("item_count"); + template.ItemId = reader.GetUInt32("item_id"); + template.KindId = reader.GetUInt32("kind_id"); + template.KindValue = reader.GetUInt32("kind_value"); + //template.label_key_string = LocalizationManager.Instance.Get("label_key_string", "label_key_string", template.Id); + template.MailBody = LocalizationManager.Instance.Get("mail_body", "mail_body", template.Id); + template.MailTitle = LocalizationManager.Instance.Get("mail_title", "mail_title", template.Id); + template.Name = LocalizationManager.Instance.Get("name", "name", template.Id); + template.OnAir = reader.GetBoolean("on_air", true); + template.ShowWhenever = reader.GetBoolean("show_whenever", true); + template.ShowWherever = reader.GetBoolean("show_wherever", true); + template.StDay = reader.GetUInt32("st_day"); + template.StHour = reader.GetUInt32("st_hour"); + template.StMin = reader.GetUInt32("st_min"); + template.StMonth = reader.GetUInt32("st_month"); + template.StYear = reader.GetUInt32("st_year"); + template.StYear = reader.GetUInt32("st_year"); + template.ToolTip = reader.GetBoolean("tool_tip", true); + template.WheneverTooltip = reader.GetBoolean("whenever_tooltip", true); + template.WhereverTooltip = reader.GetBoolean("wherever_tooltip", true); + + _scheduleItems.TryAdd(template.Id, template); + } + } + } } public void PostLoad() @@ -130,5 +184,6 @@ public void PostLoad() GameScheduleManager.Instance.LoadGameScheduleSpawners(_gameScheduleSpawners); GameScheduleManager.Instance.LoadGameScheduleDoodads(_gameScheduleDoodads); GameScheduleManager.Instance.LoadGameScheduleQuests(_gameScheduleQuests); + GameScheduleManager.Instance.LoadScheduleItems(_scheduleItems); } } diff --git a/AAEmu.Game/GameService.cs b/AAEmu.Game/GameService.cs index d14beef3c0..a733024581 100644 --- a/AAEmu.Game/GameService.cs +++ b/AAEmu.Game/GameService.cs @@ -194,6 +194,7 @@ public async Task StartAsync(CancellationToken cancellationToken) GameDataManager.Instance.PostLoadGameData(); FishSchoolManager.Instance.Initialize(); RadarManager.Instance.Initialize(); + ManaRegenManager.Instance.Initialize(); PublicFarmManager.Instance.Initialize(); if ((waterBodyTask != null) && (!waterBodyTask.IsCompleted)) diff --git a/AAEmu.Game/Models/Game/Attendance/CharacterAttendances.cs b/AAEmu.Game/Models/Game/Attendance/CharacterAttendances.cs index 979a815a43..dc5f8ab4bf 100644 --- a/AAEmu.Game/Models/Game/Attendance/CharacterAttendances.cs +++ b/AAEmu.Game/Models/Game/Attendance/CharacterAttendances.cs @@ -68,12 +68,12 @@ public void Add(Character character) var (itemId, itemCount) = AttendanceGameData.Instance.GetReward(year, month, dayCount); if (itemCount > 0 && itemId > 0) { - character.Inventory.Bag.AcquireDefaultItem(ItemTaskType.CraftActSaved, itemId, itemCount); + character.Inventory.Bag.AcquireDefaultItem(ItemTaskType.TakeScheduleItem, itemId, itemCount); } var (additionalItemId, additionalItemCount) = AttendanceGameData.Instance.GetAdditionalReward(year, month, dayCount); if (additionalItemCount > 0 && additionalItemId > 0) { - character.Inventory.Bag.AcquireDefaultItem(ItemTaskType.CraftActSaved, additionalItemId, additionalItemCount); + character.Inventory.Bag.AcquireDefaultItem(ItemTaskType.TakeScheduleItem, additionalItemId, additionalItemCount); } character.SendPacket(new SCDbAttendanceTimePacket(true, currentDate)); diff --git a/AAEmu.Game/Models/Game/Auction/AuctionBid.cs b/AAEmu.Game/Models/Game/Auction/AuctionBid.cs new file mode 100644 index 0000000000..dad124c3bf --- /dev/null +++ b/AAEmu.Game/Models/Game/Auction/AuctionBid.cs @@ -0,0 +1,34 @@ +using AAEmu.Commons.Network; + +namespace AAEmu.Game.Models.Game.Auction; + +public class AuctionBid : PacketMarshaler +{ + public ulong LotId { get; set; } + public byte WorldId { get; set; } + public uint BidderId { get; set; } + public string BidderName { get; set; } + public int Money { get; set; } + public int StackSize { get; set; } + + public override void Read(PacketStream stream) + { + LotId = stream.ReadUInt64(); + WorldId = stream.ReadByte(); + BidderId = stream.ReadUInt32(); + BidderName = stream.ReadString(); + Money = stream.ReadInt32(); + StackSize = stream.ReadInt32(); + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write(LotId); + stream.Write(WorldId); + stream.Write(BidderId); + stream.Write(BidderName); + stream.Write(Money); + stream.Write(StackSize); + return stream; + } +} diff --git a/AAEmu.Game/Models/Game/Auction/AuctionDisplay.cs b/AAEmu.Game/Models/Game/Auction/AuctionDisplay.cs new file mode 100644 index 0000000000..ab0e3e29d1 --- /dev/null +++ b/AAEmu.Game/Models/Game/Auction/AuctionDisplay.cs @@ -0,0 +1,25 @@ +using AAEmu.Commons.Network; + +namespace AAEmu.Game.Models.Game.Auction; + +public class AuctionDisplay : PacketMarshaler +{ + public AuctionLot Lot { get; set; } + + public AuctionDisplay() + { + Lot = new AuctionLot(); // Инициализация Lot + } + + public override void Read(PacketStream stream) + { + Lot.Read(stream); + } + + public override PacketStream Write(PacketStream stream) + { + Lot.Write(stream); + + return stream; + } +} diff --git a/AAEmu.Game/Models/Game/Auction/AuctionDuration.cs b/AAEmu.Game/Models/Game/Auction/AuctionDuration.cs new file mode 100644 index 0000000000..c236fb0b6c --- /dev/null +++ b/AAEmu.Game/Models/Game/Auction/AuctionDuration.cs @@ -0,0 +1,9 @@ +namespace AAEmu.Game.Models.Game.Auction; + +public enum AuctionDuration : byte +{ + AuctionDuration6Hours = 8, + AuctionDuration12Hours = 9, + AuctionDuration24Hours = 10, + AuctionDuration48Hours = 11 +} diff --git a/AAEmu.Game/Models/Game/Auction/AuctionItem.cs b/AAEmu.Game/Models/Game/Auction/AuctionItem.cs deleted file mode 100644 index 3d2a10f722..0000000000 --- a/AAEmu.Game/Models/Game/Auction/AuctionItem.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; - -using AAEmu.Commons.Network; -using AAEmu.Game.Models.Game.Items; - -using static System.Runtime.InteropServices.JavaScript.JSType; - -namespace AAEmu.Game.Models.Game.Auction; - -public class AuctionItem -{ - public ulong Id { get; set; } - public byte Duration { get; set; } - public uint ItemId { get; set; } - public ulong ObjectId { get; set; } - public byte Grade { get; set; } - public ItemFlag Flags { get; set; } - public uint StackSize { get; set; } - public byte DetailType { get; set; } - public DateTime CreationTime { get; set; } - public DateTime EndTime { get; set; } - public uint LifespanMins { get; set; } - public uint Type1 { get; set; } - public byte WorldId { get; set; } - public DateTime UnsecureDateTime { get; set; } - public DateTime UnpackDateTime { get; set; } - public byte WorldId2 { get; set; } - public uint ClientId { get; set; } - public string ClientName { get; set; } - public int StartMoney { get; set; } - public int DirectMoney { get; set; } - public ulong TimeLeft - { - get { return (ulong)EndTime.Subtract(DateTime.UtcNow).TotalSeconds; } - set => throw new NotImplementedException(); - } //seconds - public byte BidWorldId { get; set; } - public uint BidderId { get; set; } - public string BidderName { get; set; } - public int BidMoney { get; set; } - public uint Extra { get; set; } - public bool IsDirty { get; set; } - - public void Read(PacketStream stream) - { - Id = stream.ReadUInt64(); - Duration = stream.ReadByte(); - ItemId = stream.ReadUInt32(); - ObjectId = stream.ReadUInt64(); - Grade = stream.ReadByte(); - Grade = stream.ReadByte(); - StackSize = stream.ReadUInt32(); - DetailType = stream.ReadByte(); - CreationTime = stream.ReadDateTime(); - LifespanMins = stream.ReadUInt32(); - Type1 = stream.ReadUInt32(); - WorldId = stream.ReadByte(); - UnsecureDateTime = stream.ReadDateTime(); - UnpackDateTime = stream.ReadDateTime(); - WorldId2 = stream.ReadByte(); - ClientId = stream.ReadUInt32(); - ClientName = stream.ReadString(); - StartMoney = stream.ReadInt32(); - DirectMoney = stream.ReadInt32(); - TimeLeft = stream.ReadUInt64(); - BidWorldId = stream.ReadByte(); - BidderId = stream.ReadUInt32(); - BidderName = stream.ReadString(); - BidMoney = stream.ReadInt32(); - Extra = stream.ReadUInt32(); - } - - public PacketStream Write(PacketStream stream) - { - stream.Write(Id); - stream.Write(Duration); - stream.Write(ItemId); - stream.Write(ObjectId); - stream.Write(Grade); - stream.Write((byte)Flags); - stream.Write(StackSize); - stream.Write(DetailType); - stream.Write(DateTime.UtcNow); - stream.Write(LifespanMins); - stream.Write(Type1); - stream.Write(WorldId); - stream.Write(DateTime.UtcNow); - stream.Write(DateTime.UtcNow); - stream.Write(WorldId2); - stream.Write(ClientId); - stream.Write(ClientName); - stream.Write(StartMoney); - stream.Write(DirectMoney); - var Random = new Random(); - var offsett = TimeLeft + (ulong)Random.Next(0, 10); - stream.Write(offsett); - stream.Write(BidWorldId); - stream.Write(BidderId); - stream.Write(BidderName); - stream.Write(BidMoney); - stream.Write(Extra); - return stream; - - } -} diff --git a/AAEmu.Game/Models/Game/Auction/AuctionLot.cs b/AAEmu.Game/Models/Game/Auction/AuctionLot.cs new file mode 100644 index 0000000000..fee408eb03 --- /dev/null +++ b/AAEmu.Game/Models/Game/Auction/AuctionLot.cs @@ -0,0 +1,78 @@ +using System; + +using AAEmu.Commons.Network; +using AAEmu.Game.Models.Game.Items; + +namespace AAEmu.Game.Models.Game.Auction; + +public class AuctionLot : PacketMarshaler +{ + public ulong Id { get; set; } + public AuctionDuration Duration { get; set; } // 8 is 6 hours, 9 is 12 hours, 10 is 24 hours, 11 is 48 hours + public Item Item { get; set; } + public DateTime EndTime { get; set; } + public ulong TimeLeft { get => (ulong)EndTime.Subtract(DateTime.UtcNow).TotalSeconds; } // seconds left + public byte WorldId { get; set; } + public uint ClientId { get; set; } + public string ClientName { get; set; } + public int StartMoney { get; set; } + public int DirectMoney { get; set; } + public DateTime PostDate { get; set; } + public int ChargePercent { get; set; } + public byte BidWorldId { get; set; } + public uint BidderId { get; set; } + public string BidderName { get; set; } + public int BidMoney { get; set; } + public int Extra { get; set; } + public int MinStack { get; set; } + public int MaxStack { get; set; } + public bool IsDirty { get; set; } + + public override void Read(PacketStream stream) + { + Id = stream.ReadUInt64(); + Duration = (AuctionDuration)stream.ReadByte(); + + Item = new Item(); + Item.Read(stream); + + WorldId = stream.ReadByte(); + ClientId = stream.ReadUInt32(); + ClientName = stream.ReadString(); + StartMoney = stream.ReadInt32(); + DirectMoney = stream.ReadInt32(); + PostDate = DateTime.FromBinary(stream.ReadInt64()); + ChargePercent = stream.ReadInt32(); + BidWorldId = stream.ReadByte(); + BidderId = stream.ReadUInt32(); + BidderName = stream.ReadString(); + BidMoney = stream.ReadInt32(); + Extra = stream.ReadInt32(); + MinStack = stream.ReadInt32(); + MaxStack = stream.ReadInt32(); + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write(Id); + stream.Write((byte)Duration); + + stream.Write(Item); + + stream.Write(WorldId); + stream.Write(ClientId); + stream.Write(ClientName); + stream.Write(StartMoney); + stream.Write(DirectMoney); + stream.Write(PostDate); + stream.Write(ChargePercent); + stream.Write(BidWorldId); + stream.Write(BidderId); + stream.Write(BidderName); + stream.Write(BidMoney); + stream.Write(Extra); + stream.Write(MinStack); + stream.Write(MaxStack); + return stream; + } +} diff --git a/AAEmu.Game/Models/Game/Auction/AuctionSearch.cs b/AAEmu.Game/Models/Game/Auction/AuctionSearch.cs new file mode 100644 index 0000000000..a37f5a21c1 --- /dev/null +++ b/AAEmu.Game/Models/Game/Auction/AuctionSearch.cs @@ -0,0 +1,65 @@ +using AAEmu.Commons.Network; + +namespace AAEmu.Game.Models.Game.Auction; + +public class AuctionSearch : PacketMarshaler +{ + public string Keyword { get; set; } + public bool ExactMatch { get; set; } + public byte Grade { get; set; } + public byte CategoryA { get; set; } + public byte CategoryB { get; set; } + public byte CategoryC { get; set; } + public uint ClientId { get; set; } + public int Page { get; set; } + public int Filter { get; set; } + public byte WorldId { get; set; } + public byte MinItemLevel { get; set; } + public byte MaxItemLevel { get; set; } + public uint MinMoneyAmount { get; set; } + public uint MaxMoneyAmount { get; set; } + public AuctionSearchSortKind SortKind { get; set; } + public AuctionSearchSortOrder SortOrder { get; set; } + + + public override void Read(PacketStream stream) + { + Keyword = stream.ReadString(); + ExactMatch = stream.ReadBoolean(); + Grade = stream.ReadByte(); + CategoryA = stream.ReadByte(); + CategoryB = stream.ReadByte(); + CategoryC = stream.ReadByte(); + Page = stream.ReadInt32(); + ClientId = stream.ReadUInt32(); + Filter = stream.ReadInt32(); + WorldId = stream.ReadByte(); + MinItemLevel = stream.ReadByte(); + MaxItemLevel = stream.ReadByte(); + MinMoneyAmount = stream.ReadUInt32(); // moneyAmount + MaxMoneyAmount = stream.ReadUInt32(); // moneyAmount + SortKind = (AuctionSearchSortKind)stream.ReadByte(); + SortOrder = (AuctionSearchSortOrder)stream.ReadByte(); + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write(Keyword); + stream.Write(ExactMatch); + stream.Write(Grade); + stream.Write(CategoryA); + stream.Write(CategoryB); + stream.Write(CategoryC); + stream.Write(Page); + stream.Write(ClientId); + stream.Write(Filter); + stream.Write(WorldId); + stream.Write(MinItemLevel); + stream.Write(MaxItemLevel); + stream.Write(MinMoneyAmount); // moneyAmount + stream.Write(MaxMoneyAmount); // moneyAmount + stream.Write((byte)SortKind); + stream.Write((byte)SortOrder); + return stream; + } +} diff --git a/AAEmu.Game/Models/Game/Auction/AuctionSearchSortKind.cs b/AAEmu.Game/Models/Game/Auction/AuctionSearchSortKind.cs new file mode 100644 index 0000000000..1feb16d2d3 --- /dev/null +++ b/AAEmu.Game/Models/Game/Auction/AuctionSearchSortKind.cs @@ -0,0 +1,12 @@ +namespace AAEmu.Game.Models.Game.Auction; + +public enum AuctionSearchSortKind : byte +{ + Default = 0, + Evaluated = 1, + ItemName = 2, + ItemLevel = 3, + ExpireDate = 4, + BidPrice = 5, + DirectPrice = 6 +} diff --git a/AAEmu.Game/Models/Game/Auction/AuctionSearchSortOrder.cs b/AAEmu.Game/Models/Game/Auction/AuctionSearchSortOrder.cs new file mode 100644 index 0000000000..9bd2c97f27 --- /dev/null +++ b/AAEmu.Game/Models/Game/Auction/AuctionSearchSortOrder.cs @@ -0,0 +1,7 @@ +namespace AAEmu.Game.Models.Game.Auction; + +public enum AuctionSearchSortOrder : byte +{ + Asc = 0, + Desc = 1 +} diff --git a/AAEmu.Game/Models/Game/Auction/AuctionSold.cs b/AAEmu.Game/Models/Game/Auction/AuctionSold.cs new file mode 100644 index 0000000000..8f0e884c32 --- /dev/null +++ b/AAEmu.Game/Models/Game/Auction/AuctionSold.cs @@ -0,0 +1,285 @@ +using System.Collections.Generic; +using System.Linq; + +using AAEmu.Commons.Network; + +using MySql.Data.MySqlClient; + +namespace AAEmu.Game.Models.Game.Auction; + +public class AuctionSold : PacketMarshaler +{ + public int Id { get; set; } // ключ + public uint ItemId { get; set; } // Id + public int Day { get; set; } + public long MinCopper { get; set; } + public long MaxCopper { get; set; } + public long AvgCopper { get; set; } + public int Volume { get; set; } + public byte ItemGrade { get; set; } + public long WeeklyAvgCopper { get; set; } + public List Solds { get; set; } + + public AuctionSold() + { + Solds = new List(); + } + + public override void Read(PacketStream stream) + { + ItemId = stream.ReadUInt32(); + Day = stream.ReadInt32(); + MinCopper = stream.ReadInt64(); + MaxCopper = stream.ReadInt64(); + AvgCopper = stream.ReadInt64(); + Volume = stream.ReadInt32(); + ItemGrade = stream.ReadByte(); + WeeklyAvgCopper = stream.ReadInt64(); + } + + public override PacketStream Write(PacketStream stream) + { + stream.Write(ItemId); + stream.Write(Day); + stream.Write(MinCopper); + stream.Write(MaxCopper); + stream.Write(AvgCopper); + stream.Write(Volume); + stream.Write(ItemGrade); + stream.Write(WeeklyAvgCopper); + return stream; + } + + public void SaveAuctionSold(MySqlConnection connection, AuctionSold auctionSold) + { + if (connection.State != System.Data.ConnectionState.Open) + { + connection.Open(); + } + + using var command = connection.CreateCommand(); + command.CommandText = "INSERT INTO auction_sold (item_id, day, min_copper, max_copper, avg_copper, volume, item_grade, weekly_avg_copper)" + + " VALUES (@item_id, @day, @min_copper, @max_copper, @avg_copper, @volume, @item_grade, @weekly_avg_copper);"; + command.Prepare(); + command.Parameters.AddWithValue("@item_id", auctionSold.ItemId); + command.Parameters.AddWithValue("@day", auctionSold.Day); + command.Parameters.AddWithValue("@min_copper", auctionSold.MinCopper); + command.Parameters.AddWithValue("@max_copper", auctionSold.MaxCopper); + command.Parameters.AddWithValue("@avg_copper", auctionSold.AvgCopper); + command.Parameters.AddWithValue("@volume", auctionSold.Volume); + command.Parameters.AddWithValue("@item_grade", auctionSold.ItemGrade); + command.Parameters.AddWithValue("@weekly_avg_copper", auctionSold.WeeklyAvgCopper); + + command.ExecuteNonQuery(); + } + + public AuctionSold GetAuctionSoldByItemId(MySqlConnection connection, uint itemId) + { + if (connection.State != System.Data.ConnectionState.Open) + { + connection.Open(); + } + + using var command = connection.CreateCommand(); + command.CommandText = @" + SELECT id, item_id, day, min_copper, max_copper, avg_copper, volume, item_grade, weekly_avg_copper + FROM auction_sold + WHERE item_id = @item_id; + "; + command.Parameters.AddWithValue("@item_id", itemId); + + using var reader = command.ExecuteReader(); + if (reader.Read()) + { + return new AuctionSold + { + Id = reader.GetInt32("id"), + ItemId = reader.GetUInt32("item_id"), + Day = reader.GetInt32("day"), + MinCopper = reader.GetInt64("min_copper"), + MaxCopper = reader.GetInt64("max_copper"), + AvgCopper = reader.GetInt64("avg_copper"), + Volume = reader.GetInt32("volume"), + ItemGrade = reader.GetByte("item_grade"), + WeeklyAvgCopper = reader.GetInt64("weekly_avg_copper") + }; + } + + return null; + } + + public List GetAllAuctionSold(MySqlConnection connection) + { + if (connection.State != System.Data.ConnectionState.Open) + { + connection.Open(); + } + + var auctionSolds = new List(); + + using var command = connection.CreateCommand(); + command.CommandText = @" + SELECT id, item_id, day, min_copper, max_copper, avg_copper, volume, item_grade, weekly_avg_copper + FROM auction_sold; + "; + + using var reader = command.ExecuteReader(); + while (reader.Read()) + { + auctionSolds.Add(new AuctionSold + { + Id = reader.GetInt32("id"), + ItemId = reader.GetUInt32("item_id"), + Day = reader.GetInt32("day"), + MinCopper = reader.GetInt64("min_copper"), + MaxCopper = reader.GetInt64("max_copper"), + AvgCopper = reader.GetInt64("avg_copper"), + Volume = reader.GetInt32("volume"), + ItemGrade = reader.GetByte("item_grade"), + WeeklyAvgCopper = reader.GetInt64("weekly_avg_copper") + }); + } + + return auctionSolds; + } + + public void DeleteAuctionSoldByItemId(MySqlConnection connection, uint itemId) + { + if (connection.State != System.Data.ConnectionState.Open) + { + connection.Open(); + } + + using var command = connection.CreateCommand(); + command.CommandText = @" + DELETE FROM auction_sold + WHERE ItemId = @ItemId; + "; + command.Parameters.AddWithValue("@item_id", itemId); + + command.ExecuteNonQuery(); + } + + public void DeleteExcessAuctionSoldByItemId(MySqlConnection connection, uint itemId) + { + if (connection.State != System.Data.ConnectionState.Open) + { + connection.Open(); + } + + using var selectCommand = connection.CreateCommand(); + selectCommand.CommandText = @" + SELECT id + FROM auction_sold + WHERE item_id = @item_id + ORDER BY id DESC; + "; + selectCommand.Parameters.AddWithValue("@item_id", itemId); + + var idsToDelete = new List(); + + using (var reader = selectCommand.ExecuteReader()) + { + var count = 0; + while (reader.Read()) + { + if (count >= 14) + { + idsToDelete.Add(reader.GetInt32("id")); + } + count++; + } + } + + if (idsToDelete.Count > 0) + { + using var deleteCommand = connection.CreateCommand(); + deleteCommand.CommandText = "DELETE FROM auction_sold WHERE id IN (" + string.Join(",", idsToDelete) + ");"; + deleteCommand.ExecuteNonQuery(); + } + } + + public AuctionSold GetLast14AuctionSoldByItemId(MySqlConnection connection, uint itemId) + { + if (connection.State != System.Data.ConnectionState.Open) + { + connection.Open(); + } + + using var selectCommand = connection.CreateCommand(); + selectCommand.CommandText = @" + SELECT id, item_id, day, min_copper, max_copper, avg_copper, volume, item_grade, weekly_avg_copper + FROM auction_sold + WHERE item_id = @ItemId + ORDER BY id DESC + LIMIT 14; + "; + selectCommand.Parameters.AddWithValue("@item_id", itemId); + + var soldItems = new List(); + + using (var reader = selectCommand.ExecuteReader()) + { + while (reader.Read()) + { + soldItems.Add(new AuctionSold + { + Id = reader.GetInt32("id"), + ItemId = reader.GetUInt32("item_id"), + Day = reader.GetInt32("day"), + MinCopper = reader.GetInt64("min_copper"), + MaxCopper = reader.GetInt64("max_copper"), + AvgCopper = reader.GetInt64("avg_copper"), + Volume = reader.GetInt32("volume"), + ItemGrade = reader.GetByte("item_grade"), + WeeklyAvgCopper = reader.GetInt64("weekly_avg_copper") + }); + } + } + + if (soldItems.Count > 0) + { + return new AuctionSold + { + ItemId = itemId, + Solds = soldItems.ToList() + }; + } + + return null; + } + + /* + public static void Main() + { + List previousWeekData = new List { 5, 7, 9, 11, 13, 15, 17 }; + List currentWeekData = new List { 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36 }; + + List combinedData = new List(previousWeekData); + combinedData.AddRange(currentWeekData); + + List sevenDayAverages = CalculateSevenDayAverages(combinedData); + + for (int i = 0; i < sevenDayAverages.Count; i++) + { + Console.WriteLine($"Day {i + 1}: {sevenDayAverages[i]:F2}"); + } + } + */ + public static List CalculateSevenDayAverages(List data) + { + var averages = new List(); + + for (var i = 6; i < data.Count; i++) + { + double sum = 0; + for (var j = i - 6; j <= i; j++) + { + sum += data[j]; + } + averages.Add(sum / 7); + } + + return averages; + } +} diff --git a/AAEmu.Game/Models/Game/Auction/Templates/AuctionSearchTemplate.cs b/AAEmu.Game/Models/Game/Auction/Templates/AuctionSearchTemplate.cs deleted file mode 100644 index 748f245c2f..0000000000 --- a/AAEmu.Game/Models/Game/Auction/Templates/AuctionSearchTemplate.cs +++ /dev/null @@ -1,22 +0,0 @@ -using AAEmu.Game.Models.Game.Char; - -namespace AAEmu.Game.Models.Game.Auction.Templates; - -public class AuctionSearchTemplate -{ - public Character Player { get; set; } - public string ItemName { get; set; } - public bool ExactMatch { get; set; } - public byte Grade { get; set; } - public byte CategoryA { get; set; } - public byte CategoryB { get; set; } - public byte CategoryC { get; set; } - public uint Page { get; set; } - public uint PlayerId { get; set; } - public uint Filter { get; set; } - public uint WorldID { get; set; } - public byte MinItemLevel { get; set; } - public byte MaxItemLevel { get; set; } - public byte SortKind { get; set; } - public byte SortOrder { get; set; } -} diff --git a/AAEmu.Game/Models/Game/Char/Character.cs b/AAEmu.Game/Models/Game/Char/Character.cs index 7a677c1a59..75c6b7110c 100644 --- a/AAEmu.Game/Models/Game/Char/Character.cs +++ b/AAEmu.Game/Models/Game/Char/Character.cs @@ -236,6 +236,7 @@ public bool IsOnline } } public FishSchool FishSchool { get; set; } + public List ScheduleItems { get; set; } #region Attributes @@ -1206,11 +1207,12 @@ public Character(UnitCustomModelParams modelParams) _hostilePlayers = new ConcurrentDictionary(); Breath = LungCapacity; ModelParams = modelParams; - Subscribers = new List(); + Subscribers = []; ChargeLock = new object(); FishSchool = new FishSchool(this); //Events.OnDisconnect += OnDisconnect; //Events.OnCombatStarted += OnEnterCombat; + ScheduleItems = []; } public void SetHostileActivity(Character attacker) @@ -1290,14 +1292,14 @@ public void CheckExp() } } - public bool ChangeMoney(SlotType moneylocation, int amount, ItemTaskType itemTaskType = ItemTaskType.DepositMoney) => ChangeMoney(SlotType.None, moneylocation, amount, itemTaskType); + public bool ChangeMoney(SlotType moneylocation, int amount, ItemTaskType itemTaskType = ItemTaskType.DepositMoney) => ChangeMoney(SlotType.Invalid, moneylocation, amount, itemTaskType); public bool ChangeMoney(SlotType typeFrom, SlotType typeTo, int amount, ItemTaskType itemTaskType = ItemTaskType.DepositMoney) { var itemTasks = new List(); switch (typeFrom) { - case SlotType.Inventory: + case SlotType.Bag: if (amount > Money) { SendErrorMessage(ErrorMessageType.NotEnoughMoney); @@ -1318,7 +1320,7 @@ public bool ChangeMoney(SlotType typeFrom, SlotType typeTo, int amount, ItemTask } switch (typeTo) { - case SlotType.Inventory: + case SlotType.Bag: Money += amount; itemTasks.Add(new MoneyChange(amount)); break; @@ -1335,14 +1337,14 @@ public bool AddMoney(SlotType moneyLocation, int amount, ItemTaskType itemTaskTy { if (amount < 0) return false; - return ChangeMoney(SlotType.None, moneyLocation, amount, itemTaskType); + return ChangeMoney(SlotType.Invalid, moneyLocation, amount, itemTaskType); } public bool SubtractMoney(SlotType moneyLocation, int amount, ItemTaskType itemTaskType = ItemTaskType.DepositMoney) { if (amount < 0) return false; - return ChangeMoney(SlotType.None, moneyLocation, -amount, itemTaskType); + return ChangeMoney(SlotType.Invalid, moneyLocation, -amount, itemTaskType); } public void ChangeLabor(short change, int actabilityId) @@ -2217,7 +2219,7 @@ public void Load() { var template = CharacterManager.Instance.GetTemplate(Race, Gender); ModelId = template.ModelId; - BuyBackItems = new ItemContainer(Id, SlotType.None, false, this); + BuyBackItems = new ItemContainer(Id, SlotType.StoreGood, false, this); Slots = new ActionSlot[MaxActionSlots]; for (var i = 0; i < Slots.Length; i++) Slots[i] = new ActionSlot(); diff --git a/AAEmu.Game/Models/Game/Char/CharacterActability.cs b/AAEmu.Game/Models/Game/Char/CharacterActability.cs index c148262026..031a5170d0 100644 --- a/AAEmu.Game/Models/Game/Char/CharacterActability.cs +++ b/AAEmu.Game/Models/Game/Char/CharacterActability.cs @@ -83,7 +83,7 @@ public void ExpandExpert() return; // TODO ... send msg error? } - if (expand.ItemId != 0 && expand.ItemCount != 0 && !Owner.Inventory.CheckItems(Items.SlotType.Inventory, expand.ItemId, expand.ItemCount)) + if (expand.ItemId != 0 && expand.ItemCount != 0 && !Owner.Inventory.CheckItems(Items.SlotType.Bag, expand.ItemId, expand.ItemCount)) { Owner.SendErrorMessage(ErrorMessageType.NotEnoughExpandItem); return; // TODO ... send msg error? diff --git a/AAEmu.Game/Models/Game/Char/CharacterCraft.cs b/AAEmu.Game/Models/Game/Char/CharacterCraft.cs index bd59e9d687..067a98e470 100644 --- a/AAEmu.Game/Models/Game/Char/CharacterCraft.cs +++ b/AAEmu.Game/Models/Game/Char/CharacterCraft.cs @@ -144,7 +144,7 @@ public void EndCraft() return; } - if (Owner.Inventory.FreeSlotCount(SlotType.Inventory) < _craft.CraftProducts.Count) + if (Owner.Inventory.FreeSlotCount(SlotType.Bag) < _craft.CraftProducts.Count) { // TODO not verified Owner.SendErrorMessage(ErrorMessageType.CraftCantActAnyMore, ErrorMessageType.NotEnoughSpace, 0, false); diff --git a/AAEmu.Game/Models/Game/Char/CharacterMails.cs b/AAEmu.Game/Models/Game/Char/CharacterMails.cs index 0bf9e87c6d..3b640a7821 100644 --- a/AAEmu.Game/Models/Game/Char/CharacterMails.cs +++ b/AAEmu.Game/Models/Game/Char/CharacterMails.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Linq; using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Char; @@ -13,6 +15,7 @@ public class CharacterMails { public Character Self { get; set; } public CountUnreadMail UnreadMailCount { get; set; } + private int SendMailIndex { get; set; } public CharacterMails(Character self) { @@ -20,34 +23,60 @@ public CharacterMails(Character self) UnreadMailCount = new CountUnreadMail { - TotalSent = 0, - TotalReceived = 0, - TotalMiaReceived = 0, - TotalCommercialReceived = 0 + TotalSent = 0 }; UnreadMailCount.ResetReceived(); } - public void OpenMailbox(byte mailBoxListKind) + public void SendMailList(byte mailBoxListKind, int startIdx, int sentCnt, bool isRecover, bool isTest) { - var mailList = MailManager.Instance.GetCurrentMailList(Self); + SendMailIndex = 0; + + var mailList = MailManager.Instance.GetCurrentMailList(Self).Values.ToList(); var total = mailList.Count; - foreach (var m in mailList) + + SendMailList(mailBoxListKind, mailList[SendMailIndex].Header, total); + + SendMailIndex++; + + if (SendMailIndex < total - 1) { - if (m.Value.Header.SenderId == Self.Id && m.Value.Header.ReceiverId == Self.Id) - { - Self.SendPacket(new SCMailListPacket(false, total, m.Value.Header, mailBoxListKind)); - } - else if (m.Value.Header.SenderId == Self.Id) - { - Self.SendPacket(new SCMailListPacket(false, total, m.Value.Header, mailBoxListKind)); - } - else if (m.Value.Header.ReceiverId == Self.Id) - { - Self.SendPacket(new SCMailListPacket(false, total, m.Value.Header, mailBoxListKind)); - } + return; } + Self.SendPacket(new SCMailListEndPacket((byte)total, UnreadMailCount)); + SendMailIndex = 0; + } + + public void SendMailListContinue(byte mailBoxListKind) + { + var mailList = MailManager.Instance.GetCurrentMailList(Self).Values.ToList(); + var total = mailList.Count; + + if (SendMailIndex < total) + { + SendMailList(mailBoxListKind, mailList[SendMailIndex].Header, total); + SendMailIndex++; + return; + } + + Self.SendPacket(new SCMailListEndPacket(mailBoxListKind, UnreadMailCount)); + } + + private void SendMailList(byte mailBoxListKind, MailHeader mailHeader, int total) + { + if (mailHeader.SenderId == Self.Id && mailHeader.ReceiverId == Self.Id) + { + Self.SendPacket(new SCMailListPacket(false, total, mailHeader, mailBoxListKind)); + } + else if (mailHeader.SenderId == Self.Id) + { + Self.SendPacket(new SCMailListPacket(false, total, mailHeader, mailBoxListKind)); + } + else if (mailHeader.ReceiverId == Self.Id) + { + Self.SendPacket(new SCMailListPacket(false, total, mailHeader, mailBoxListKind)); + } } public void ReadMail(bool isSent, long id) @@ -56,14 +85,14 @@ public void ReadMail(bool isSent, long id) { if (mail.Header.Status == MailStatus.Unread && !isSent) { - UnreadMailCount.UpdateReceived(mail.MailType, -1); + UnreadMailCount.UpdateUnreadReceived(mail.MailType, -1); mail.OpenDate = DateTime.UtcNow; mail.Header.Status = MailStatus.Read; mail.IsDelivered = true; } Self.SendPacket(new SCMailBodyPacket(false, isSent, mail.Body, true, UnreadMailCount)); - Self.SendPacket(new SCMailStatusUpdatedPacket(isSent, id, mail.Header.Status)); - SendUnreadMailCount(); + //Self.SendPacket(new SCMailStatusUpdatedPacket(isSent, id, mail.Header.Status)); + //SendUnreadMailCount(); } } @@ -74,12 +103,12 @@ public void SendUnreadMailCount() public MailResult SendMailToPlayer(MailType mailType, string receiverName, string title, string text, byte attachments, int money0, int money1, int money2, long extra, List<(SlotType, byte)> itemSlots) { - + if (string.IsNullOrWhiteSpace(receiverName) || NameManager.Instance.GetCharacterId(receiverName) == 0) { return MailResult.UnableToFindRecipient; } - + var mail = new MailPlayerToPlayer(Self, receiverName); mail.MailType = mailType; @@ -123,7 +152,7 @@ public MailResult SendMailToPlayer(MailType mailType, string receiverName, strin { Self.SendPacket(new SCMailSentPacket(mail.Header, itemSlots.ToArray(), UnreadMailCount)); // Take the fee - Self.SubtractMoney(SlotType.Inventory, mailFee + money0); + Self.SubtractMoney(SlotType.Bag, mailFee + money0); return MailResult.Success; } else @@ -152,12 +181,15 @@ public bool GetAttached(long mailId, bool takeMoney, bool takeItems, bool takeAl } if (thisMail.Body.CopperCoins > 0 && takeMoney) { - Self.ChangeMoney(SlotType.Inventory, thisMail.Body.CopperCoins); + Self.ChangeMoney(SlotType.Bag, thisMail.Body.CopperCoins); thisMail.Body.CopperCoins = 0; thisMail.Header.Attachments -= 1; tookMoney = true; } + if (thisMail.Body.CopperCoins == 0 && takeMoney) + takeMoney = false; + var itemSlotList = new List(); // Check if items need to be taken, and add them to a list if (takeItems) @@ -277,10 +309,12 @@ public void DeleteMail(long id, bool isSent) if (MailManager.Instance._allPlayerMails[id].Header.Status != MailStatus.Read) { UnreadMailCount.UpdateReceived(MailManager.Instance._allPlayerMails[id].MailType, -1); + UnreadMailCount.UpdateUnreadReceived(MailManager.Instance._allPlayerMails[id].MailType, -1); Self.SendPacket(new SCMailDeletedPacket(isSent, id, true, UnreadMailCount)); } else { + UnreadMailCount.UpdateReceived(MailManager.Instance._allPlayerMails[id].MailType, -1); Self.SendPacket(new SCMailDeletedPacket(isSent, id, false, UnreadMailCount)); } @@ -298,7 +332,7 @@ public void ReturnMail(long id) for (var i = 0; i < MailBody.MaxMailAttachments; i++) { var item = ItemManager.Instance.GetItemByItemId(thisMail.Body.Attachments[i].Id); - if (item.SlotType == SlotType.None) + if (item.SlotType == SlotType.Invalid) { itemSlots.Add(((byte)0, (byte)0)); } diff --git a/AAEmu.Game/Models/Game/Char/CharacterMates.cs b/AAEmu.Game/Models/Game/Char/CharacterMates.cs index 146c9bc2e5..a401df4bfc 100644 --- a/AAEmu.Game/Models/Game/Char/CharacterMates.cs +++ b/AAEmu.Game/Models/Game/Char/CharacterMates.cs @@ -134,7 +134,7 @@ public void SpawnMount(SkillItem skillData) buff.Apply(mount, obj, mount, null, null, new EffectSource(), null, DateTime.UtcNow); } - mount.Equipment = ItemManager.Instance.GetItemContainerForCharacter(Owner.Id, SlotType.EquipmentMate, mount, mount.Id); + mount.Equipment = ItemManager.Instance.GetItemContainerForCharacter(Owner.Id, SlotType.PetRideEquipment, mount, mount.Id); mount.UpdateGearBonuses(null, null); // Cap stats to their max diff --git a/AAEmu.Game/Models/Game/Char/CharacterPortals.cs b/AAEmu.Game/Models/Game/Char/CharacterPortals.cs index 21c5088a4f..4ad32db345 100644 --- a/AAEmu.Game/Models/Game/Char/CharacterPortals.cs +++ b/AAEmu.Game/Models/Game/Char/CharacterPortals.cs @@ -1,9 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Managers.Id; using AAEmu.Game.Core.Packets.G2C; +using AAEmu.Game.Models.Game.Units; using MySql.Data.MySqlClient; @@ -112,6 +114,70 @@ public bool ChangePrivatePortalName(uint id, string name) return false; } + + public void AddOrUpdatePrivatePortal(float x, float y, float z, float zRot, uint zoneId, string name) + { + // Проверка на null + if (Owner == null) + { + throw new InvalidOperationException("Owner cannot be null."); + } + + // Проверка на пустоту имени + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentException("Portal name cannot be null or empty.", nameof(name)); + } + + // Поиск существующего портала с такими же координатами и zoneId + var tolerance = 0.0001; + var existingPortal = PrivatePortals.Values.FirstOrDefault(p => + Math.Abs(p.X - x) < tolerance && + Math.Abs(p.Y - y) < tolerance && + Math.Abs(p.Z - z) < tolerance && + p.ZoneId.Equals(zoneId)); + + if (existingPortal != null) + { + //RemoveFromBookPortal(existingPortal, true); + + // Обновление имени существующего портала + existingPortal.Name = name; + existingPortal.ZRot = zRot; // Обновление ZRot, если это необходимо + // Добавление портала в список + //PrivatePortals.Add(existingPortal.Id, existingPortal); + + // Отправка пакета владельцу с обновленным порталом + Owner.SendPacket(new SCPortalInfoSavedPacket(existingPortal)); + //Send(); + } + else + { + // Получение нового уникального Id + var newId = PrivateBookIdManager.Instance.GetNextId(); + + // Создание нового портала + var newPortal = new Portal + { + Id = newId, + Name = name, + X = x, + Y = y, + Z = z, + ZoneId = zoneId, + ZRot = zRot, + Owner = Owner.Id + }; + + // Добавление портала в список + PrivatePortals.Add(newPortal.Id, newPortal); + + // Отправка пакета владельцу с новым порталом + Owner.SendPacket(new SCPortalInfoSavedPacket(newPortal)); + //Send(); + } + } + public void SendIndunZone() { Owner.SendPacket(new SCIndunZone([])); diff --git a/AAEmu.Game/Models/Game/Char/CharacterQuests.cs b/AAEmu.Game/Models/Game/Char/CharacterQuests.cs index 099c1fdb75..d6ef2420d3 100644 --- a/AAEmu.Game/Models/Game/Char/CharacterQuests.cs +++ b/AAEmu.Game/Models/Game/Char/CharacterQuests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Data; @@ -9,13 +9,12 @@ using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.GameData; -using AAEmu.Game.Models.Game.Faction; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Quests; using AAEmu.Game.Models.Game.Quests.Acts; using AAEmu.Game.Models.Game.Quests.Static; using AAEmu.Game.Models.Game.Quests.Templates; -using AAEmu.Game.Models.StaticValues; + using MySql.Data.MySqlClient; using NLog; @@ -88,7 +87,7 @@ public bool AddQuest(uint questId, bool forcibly = false, QuestAcceptorType ques { if (!UnitRequirementsGameData.Instance.CanComponentRun(questComponentTemplate, Owner)) { - Logger.Trace($"User {Owner.Name} ({Owner.Id}) does not meet requirements to start new Quest {questId}, ComponentId {questComponentTemplate.Id}"); + Logger.Debug($"User {Owner.Name} ({Owner.Id}) does not meet requirements to start new Quest {questId}, ComponentId {questComponentTemplate.Id}"); if (!forcibly) return false; } diff --git a/AAEmu.Game/Models/Game/Char/Inventory.cs b/AAEmu.Game/Models/Game/Char/Inventory.cs index 8e97fc04bb..e7aae53277 100644 --- a/AAEmu.Game/Models/Game/Char/Inventory.cs +++ b/AAEmu.Game/Models/Game/Char/Inventory.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.Linq; +using AAEmu.Commons.Cryptography; using AAEmu.Commons.Network; +using AAEmu.Commons.Utils; using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Managers.UnitManagers; using AAEmu.Game.Core.Packets.G2C; @@ -31,6 +33,7 @@ public class Inventory public ItemContainer Warehouse { get; private set; } public ItemContainer MailAttachments { get; private set; } public ItemContainer SystemContainer { get; private set; } + public ItemContainer AuctionAttachments { get; private set; } public ulong PreviousBackPackItemId { get; set; } // used to re-equip glider when putting backpacks down public Inventory(ICharacter owner) @@ -47,7 +50,7 @@ public Inventory(ICharacter owner) { var st = (SlotType)stv; - if (st == SlotType.EquipmentMate || st == SlotType.EquipmentSlave) + if (st == SlotType.PetRideEquipment || st == SlotType.SlaveEquipment) continue; // Take Equipment Container from Parent Unit's Equipment @@ -71,7 +74,7 @@ public Inventory(ICharacter owner) Equipment = newContainer; break; */ - case SlotType.Inventory: + case SlotType.Bag: newContainer.ContainerSize = Owner.NumInventorySlots; Bag = newContainer; break; @@ -79,10 +82,13 @@ public Inventory(ICharacter owner) newContainer.ContainerSize = Owner.NumBankSlots; Warehouse = newContainer; break; - case SlotType.Mail: + case SlotType.MailAttachment: MailAttachments = newContainer; break; - case SlotType.System: + case SlotType.Auction: + AuctionAttachments = newContainer; + break; + case SlotType.Money: SystemContainer = newContainer; break; } @@ -112,7 +118,7 @@ public void Load(MySqlConnection connection, SlotType? slotType = null) // Place loaded items list in correct containers foreach (var item in playeritems) { - if (item.SlotType != SlotType.None && _itemContainers.TryGetValue(item.SlotType, out var container)) + if (item.SlotType != SlotType.Invalid && _itemContainers.TryGetValue(item.SlotType, out var container)) { if (!container.AddOrMoveExistingItem(ItemTaskType.Invalid, item, item.Slot)) { @@ -120,6 +126,7 @@ public void Load(MySqlConnection connection, SlotType? slotType = null) Logger.Error("LoadInventory found unused item type for item, Id {0} ({1}) at {2}:{3} for {4}", item.Id, item.TemplateId, item.SlotType, item.Slot, Owner?.Name ?? "Id:" + item.OwnerId); + EncryptionManager.needNewkey1 = true; } } else @@ -138,7 +145,7 @@ public void Load(MySqlConnection connection, SlotType? slotType = null) public void Send() { Owner.SendPacket(new SCCharacterInvenInitPacket(Owner.NumInventorySlots, (uint)Owner.NumBankSlots)); - SendFragmentedInventory(SlotType.Inventory, Owner.NumInventorySlots, Bag.GetSlottedItemsList().ToArray()); + SendFragmentedInventory(SlotType.Bag, Owner.NumInventorySlots, Bag.GetSlottedItemsList().ToArray()); SendFragmentedInventory(SlotType.Bank, (byte)Owner.NumBankSlots, Warehouse.GetSlottedItemsList().ToArray()); SetInitialItemExpirationTimers(Owner.Equipment.Items.ToArray()); } @@ -160,7 +167,7 @@ public int ConsumeItem(SlotType[] containersToCheck, ItemTaskType taskType, uint if ((containersToCheck != null) && (containersToCheck.Length > 0)) containerList = containersToCheck; else - containerList = new SlotType[3] { SlotType.Inventory, SlotType.Equipment, SlotType.Bank }; + containerList = new SlotType[3] { SlotType.Bag, SlotType.Equipment, SlotType.Bank }; var res = 0; foreach (var cli in containerList) { @@ -237,7 +244,7 @@ public bool GetAllItemsByTemplate(SlotType[] inContainerTypes, uint templateId, unitsOfItemFound = 0; if (inContainerTypes == null || inContainerTypes.Length <= 0) { - inContainerTypes = new SlotType[3] { SlotType.Inventory, SlotType.Equipment, SlotType.Bank }; + inContainerTypes = new SlotType[3] { SlotType.Bag, SlotType.Equipment, SlotType.Bank }; } foreach (var ct in inContainerTypes) { @@ -282,6 +289,7 @@ public bool SplitOrMoveItem(ItemTaskType taskType, ulong fromItemId, SlotType fr if (fromItem == null && fromItemId != 0) { Logger.Error($"SplitOrMoveItem - ItemId {fromItemId} no longer exists, possibly a phantom item."); + EncryptionManager.needNewkey1 = true; return false; } @@ -289,6 +297,7 @@ public bool SplitOrMoveItem(ItemTaskType taskType, ulong fromItemId, SlotType fr if (toItem == null && toItemId != 0) { Logger.Error($"SplitOrMoveItem - ItemId {toItemId} no longer exists, possibly a phantom item."); + EncryptionManager.needNewkey1 = true; return false; } @@ -308,6 +317,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain if (fromItem == null && fromItemId != 0) { Logger.Error($"SplitOrMoveItem - ItemId {fromItemId} no longer exists, possibly a phantom item."); + EncryptionManager.needNewkey1 = true; return false; } @@ -327,11 +337,13 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain if (targetContainer is not null && !targetContainer.CanAccept(fromItem, toSlot)) { Logger.Error($"SplitOrMoveItem - fromItemId {fromItemId} is not welcome in this container {targetContainer.ContainerType} ({targetContainer.ContainerId})."); + EncryptionManager.needNewkey1 = true; return false; } if (sourceContainer is not null && !sourceContainer.CanAccept(itemInTargetSlot, fromSlot)) { Logger.Error($"SplitOrMoveItem - toItemId {toItemId} is not welcome in this container {sourceContainer.ContainerType} ({sourceContainer.ContainerId})."); + EncryptionManager.needNewkey1 = true; return false; } @@ -343,7 +355,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain } // Are we equipping it into an empty mount gear slot? - if (fromItemId == 0 && fromType == SlotType.EquipmentMate && toType != SlotType.EquipmentMate && itemInTargetSlot != null) + if (fromItemId == 0 && fromType == SlotType.PetRideEquipment && toType != SlotType.PetRideEquipment && itemInTargetSlot != null) { action = SwapAction.doEquipInEmptySlot; // In case of MateEquipment the source container is always sent as the pet's container, @@ -355,6 +367,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain if (action != SwapAction.doEquipInEmptySlot && fromItem == null) { Logger.Error("SplitOrMoveItem didn't provide a source itemId"); + EncryptionManager.needNewkey1 = true; return false; } @@ -362,6 +375,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain if (action != SwapAction.doEquipInEmptySlot && sourceContainer?.ContainerType != fromType) { Logger.Error("SplitOrMoveItem Source Item Container did not match what the client asked"); + EncryptionManager.needNewkey1 = true; return false; } @@ -369,6 +383,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain if (action != SwapAction.doEquipInEmptySlot && fromItem?.Slot != fromSlot) { Logger.Error("SplitOrMoveItem Source Item slot did not match what the client asked"); + EncryptionManager.needNewkey1 = true; return false; } @@ -376,6 +391,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain if (action != SwapAction.doEquipInEmptySlot && count > fromItem?.Count) { Logger.Error("SplitOrMoveItem Source Item has less item count than is requested to be moved"); + EncryptionManager.needNewkey1 = true; return false; } @@ -386,6 +402,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain if (itemInTargetSlot.SlotType != toType) { Logger.Error("SplitOrMoveItem Target Item Type does not match"); + EncryptionManager.needNewkey1 = true; return false; } @@ -393,6 +410,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain if (itemInTargetSlot.Slot != toSlot) { Logger.Error("SplitOrMoveItem Target Item Slot does not match"); + EncryptionManager.needNewkey1 = true; return false; } @@ -400,6 +418,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain if (action != SwapAction.doEquipInEmptySlot && itemInTargetSlot.TemplateId == fromItem?.TemplateId && itemInTargetSlot.Count + count > fromItem.Template.MaxCount && fromItem.Template.MaxCount > 1) { Logger.Error("SplitOrMoveItem Target Item stack does not have enough room to take source"); + EncryptionManager.needNewkey1 = true; return false; } } @@ -550,6 +569,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain var ni = ItemManager.Instance.Create(fromItem.TemplateId, count, fromItem.Grade, true); ni.SlotType = toType; ni.Slot = toSlot; + ni.OwnerId = targetContainer?.OwnerId ?? 0; ni._holdingContainer = targetContainer; targetContainer.Items.Add(ni); itemTasks.Add(new ItemAdd(ni)); @@ -617,6 +637,7 @@ public bool SplitOrMoveItemEx(ItemTaskType taskType, ItemContainer sourceContain // Should be impossible to get here Owner.SendMessage("|cFFFF0000SplitOrMoveItem swap action not implemented " + action + "|r"); Logger.Error("SplitOrMoveItem swap action not implemented " + action); + EncryptionManager.needNewkey1 = true; break; } @@ -690,7 +711,7 @@ public bool TakeoffBackpack(ItemTaskType taskType, bool glidersOnly = false) if (Bag.FreeSlotCount <= 0) return false; - if (!SplitOrMoveItem(taskType, backpack.Id, backpack.SlotType, (byte)backpack.Slot, 0, SlotType.Inventory, (byte)Bag.GetUnusedSlot(-1))) + if (!SplitOrMoveItem(taskType, backpack.Id, backpack.SlotType, (byte)backpack.Slot, 0, SlotType.Bag, (byte)Bag.GetUnusedSlot(-1))) return false; if (glidersOnly) @@ -745,7 +766,7 @@ public Item GetItemById(ulong id) { foreach (var c in _itemContainers) { - if (c.Key == SlotType.Equipment || c.Key == SlotType.Inventory || c.Key == SlotType.Bank) + if (c.Key == SlotType.Equipment || c.Key == SlotType.Bag || c.Key == SlotType.Bank) { foreach (var i in c.Value.Items) { @@ -778,22 +799,22 @@ public Item GetItem(SlotType type, byte slot) Item item = null; switch (type) { - case SlotType.None: + case SlotType.Invalid: // TODO ... break; case SlotType.Equipment: item = Equipment.GetItemBySlot(slot); break; - case SlotType.Inventory: + case SlotType.Bag: item = Bag.GetItemBySlot(slot); break; case SlotType.Bank: item = Warehouse.GetItemBySlot(slot); break; - case SlotType.Trade: + case SlotType.Coffer: // TODO ... break; - case SlotType.Mail: + case SlotType.MailAttachment: // TODO ... break; } @@ -828,17 +849,17 @@ private void SetInitialItemExpirationTimers(Item[] bag) private void SendFragmentedInventory(SlotType slotType, byte numItems, Item[] bag) { - var tempItem = new Item[50]; - if (numItems % 50 != 0) Logger.Warn($"SendFragmentedInventory: Inventory Size not a multiple of 50 ({numItems})"); if (bag.Length != numItems) Logger.Warn($"SendFragmentedInventory: Inventory Size Mismatch; expected {numItems} got {bag.Length}"); - for (byte chunk = 0; chunk < numItems / 50; chunk++) + byte numChunks = 0; + var dividedArrays = Helpers.SplitArray(bag, 50); // Разделяем массив на массивы по 50 значений + foreach (var item in dividedArrays) { - Array.Copy(bag, chunk * 50, tempItem, 0, 50); - Owner.SendPacket(new SCCharacterInvenContentsPacket(slotType, 1, chunk, tempItem)); + var idx = numChunks++ * 5; + Owner.SendPacket(new SCCharacterInvenContentsPacket(slotType, 5, (byte)idx, item)); } SetInitialItemExpirationTimers(bag); @@ -865,9 +886,9 @@ public void ExpandSlot(SlotType slotType) return; } - if (expand.ItemId != 0 && expand.ItemCount != 0 && !CheckItems(SlotType.Inventory, expand.ItemId, expand.ItemCount)) + if (expand.ItemId != 0 && expand.ItemCount != 0 && !CheckItems(SlotType.Bag, expand.ItemId, expand.ItemCount)) { - Logger.Warn("Item or Count not fount."); + Logger.Warn("Item or Count not found."); return; } @@ -896,7 +917,7 @@ public void ExpandSlot(SlotType slotType) Owner.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.DepositMoney, tasks, new List())); Owner.SendPacket(new SCInvenExpandedPacket( - isBank ? SlotType.Bank : SlotType.Inventory, + isBank ? SlotType.Bank : SlotType.Bag, isBank ? (byte)Owner.NumBankSlots : Owner.NumInventorySlots)); } @@ -951,12 +972,12 @@ public bool SwapCofferItems(ulong fromItemId, ulong toItemId, SlotType fromSlotT ItemContainer sourceContainer = null; ItemContainer targetContainer = null; - if (fromSlotType == SlotType.Trade) + if (fromSlotType == SlotType.Coffer) sourceContainer = relatedCoffer; else if (_itemContainers.TryGetValue(fromSlotType, out var sC)) sourceContainer = sC; - if (toSlotType == SlotType.Trade) + if (toSlotType == SlotType.Coffer) targetContainer = relatedCoffer; else if (_itemContainers.TryGetValue(toSlotType, out var tC)) targetContainer = tC; @@ -964,11 +985,11 @@ public bool SwapCofferItems(ulong fromItemId, ulong toItemId, SlotType fromSlotT if (sourceContainer == null || targetContainer == null) { Logger.Error("SwapCofferItems, not all of the targetted containers exist"); + EncryptionManager.needNewkey1 = true; return false; } - return SplitOrMoveItemEx(ItemTaskType.SwapCofferItems, sourceContainer, targetContainer, fromItemId, fromSlotType, fromSlot, - toItemId, toSlotType, toSlot); + return SplitOrMoveItemEx(ItemTaskType.SwapCofferItems, sourceContainer, targetContainer, fromItemId, fromSlotType, fromSlot, toItemId, toSlotType, toSlot); } public bool SplitCofferItems(int count, ulong fromItemId, ulong toItemId, SlotType fromSlotType, byte fromSlot, SlotType toSlotType, byte toSlot, ulong dbId) @@ -980,12 +1001,12 @@ public bool SplitCofferItems(int count, ulong fromItemId, ulong toItemId, SlotTy ItemContainer sourceContainer = null; ItemContainer targetContainer = null; - if (fromSlotType == SlotType.Trade) + if (fromSlotType == SlotType.Coffer) sourceContainer = relatedCoffer; else if (_itemContainers.TryGetValue(fromSlotType, out var sC)) sourceContainer = sC; - if (toSlotType == SlotType.Trade) + if (toSlotType == SlotType.Coffer) targetContainer = relatedCoffer; else if (_itemContainers.TryGetValue(toSlotType, out var tC)) targetContainer = tC; @@ -993,11 +1014,11 @@ public bool SplitCofferItems(int count, ulong fromItemId, ulong toItemId, SlotTy if (sourceContainer == null || targetContainer == null) { Logger.Error("SwapCofferItems, not all of the targetted containers exist"); + EncryptionManager.needNewkey1 = true; return false; } - return SplitOrMoveItemEx(ItemTaskType.SplitCofferItems, sourceContainer, targetContainer, fromItemId, fromSlotType, fromSlot, - toItemId, toSlotType, toSlot, count); + return SplitOrMoveItemEx(ItemTaskType.SplitCofferItems, sourceContainer, targetContainer, fromItemId, fromSlotType, fromSlot, toItemId, toSlotType, toSlot, count); } #region CharacterInfo_3EB0 diff --git a/AAEmu.Game/Models/Game/DoodadObj/Doodad.cs b/AAEmu.Game/Models/Game/DoodadObj/Doodad.cs index 0494e88eb6..e62d0a1ee2 100644 --- a/AAEmu.Game/Models/Game/DoodadObj/Doodad.cs +++ b/AAEmu.Game/Models/Game/DoodadObj/Doodad.cs @@ -667,14 +667,32 @@ public override void RemoveVisibleObject(Character character) base.RemoveVisibleObject(character); character.SendPacket(new SCDoodadRemovedPacket(ObjId)); } + + /// + /// GetItemTemplateIdByDoodadTemplateId - если doodad это backpack, то вернуть TemplateId предмета, который заменит этот doodad у персонажа. + /// + /// + /// + private uint GetItemTemplateIdByDoodadTemplateId(uint doodadTemplateId) + { + + return 0; + } public PacketStream Write(PacketStream stream) { stream.WriteBc(ObjId); //The object # in the list // TemplateId - The template id needed for that object, the client then uses the template configurations, not the server // CurrentPhaseId / FuncGroupId - doodad_func_group_id + // Здесь должны вставить: doodadTemplateId -> itemTemplateId + // можно найти: backpack_doodad_id->PutdownBackPackEffect->effect->skill_effect->skill->templateId + // ItemTemplateId от BackPack, который лежит на земле: Item->skill->PutdownBackPackEffect->backpack_doodad_id + // Doodad ID=7794 Solzreed Dried Food [Interaction - Backpack] -> ID=31857 Solzreed Dried Food -> Skill ID=24870 Drop Specialty + // PutdownBackPackEffect : backpack_doodad_id->effect_id, // QuestGlow - When this is higher than 0 it shows a blue orb over the doodad - stream.WritePisc(TemplateId, FuncGroupId, 0, QuestGlow); + var backpack = GetItemTemplateIdByDoodadTemplateId(TemplateId); + + stream.WritePisc(TemplateId, FuncGroupId, backpack, QuestGlow); stream.Write(Flag); stream.WriteBc(OwnerObjId); //The creator of the object @@ -708,7 +726,7 @@ public PacketStream Write(PacketStream stream) stream.Write((byte)OwnerType); // ownerType stream.Write(OwnerDbId); // dbHouseId stream.Write(Data); // data - attachPointId для хранения в базе данных - if (Flag == 3 || Flag == 8) + if (backpack != 0) { stream.Write(FreshnessTime); // freshnessTime stream.Write((uint)0); // type crafter? @@ -735,8 +753,8 @@ public override void Delete() { var item = ItemManager.Instance.GetItemByItemId(ItemId); if (item != null && item._holdingContainer != null && - (item._holdingContainer.ContainerType == SlotType.None || - item._holdingContainer.ContainerType == SlotType.System)) + (item._holdingContainer.ContainerType == SlotType.Invalid || + item._holdingContainer.ContainerType == SlotType.Money)) { item._holdingContainer.RemoveItem(ItemTaskType.Invalid, item, true); } diff --git a/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncBuyFish.cs b/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncBuyFish.cs index 84a7461f90..4be9896aa4 100644 --- a/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncBuyFish.cs +++ b/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncBuyFish.cs @@ -31,7 +31,7 @@ public override void Use(BaseUnit caster, Doodad owner, uint skillId, int nextPh character.Money += total; character.Equipment.RemoveItem(ItemTaskType.SkillEffectConsumption, backpack, true); - character.AddMoney(SlotType.Inventory, total); + character.AddMoney(SlotType.Bag, total); } } } diff --git a/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncLootItem.cs b/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncLootItem.cs index c4e2fdc28f..74ed2f830f 100644 --- a/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncLootItem.cs +++ b/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncLootItem.cs @@ -41,7 +41,7 @@ public override void Use(BaseUnit caster, Doodad owner, uint skillId, int nextPh if (ItemId == 500) { character.Money += count; - res = character.AddMoney(SlotType.Inventory, count); + res = character.AddMoney(SlotType.Bag, count); } else { diff --git a/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncRecoverItem.cs b/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncRecoverItem.cs index ffe667123a..f560ffe487 100644 --- a/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncRecoverItem.cs +++ b/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncRecoverItem.cs @@ -25,7 +25,7 @@ public override void Use(BaseUnit caster, Doodad owner, uint skillId, int nextPh { // Recoverable doodads, should be referencing a item in a System container, if this is not the case, // that means that it was already picked up by somebody else - if (item._holdingContainer?.ContainerType != SlotType.System) + if (item._holdingContainer?.ContainerType != SlotType.Money) { owner.ToNextPhase = false; character.SendErrorMessage(ErrorMessageType.InteractionRecoverParent); // TODO: Not sure what error I need to put here diff --git a/AAEmu.Game/Models/Game/DoodadObj/Static/AttachUnitReason.cs b/AAEmu.Game/Models/Game/DoodadObj/Static/AttachUnitReason.cs index cf6ef0ce94..89e9ba9e6f 100644 --- a/AAEmu.Game/Models/Game/DoodadObj/Static/AttachUnitReason.cs +++ b/AAEmu.Game/Models/Game/DoodadObj/Static/AttachUnitReason.cs @@ -14,5 +14,7 @@ public enum AttachUnitReason : byte InitFromNub = 9, PrefabChanged = 10, TransferBinding = 11, - HousingSlaveBinding = 12 + HousingSlaveBinding = 12, + unk14 = 14, + SlaveUnbinding = 15 } diff --git a/AAEmu.Game/Models/Game/ErrorMessageType.cs b/AAEmu.Game/Models/Game/ErrorMessageType.cs index 3e501171d3..4854196224 100644 --- a/AAEmu.Game/Models/Game/ErrorMessageType.cs +++ b/AAEmu.Game/Models/Game/ErrorMessageType.cs @@ -1,973 +1,1056 @@ public enum ErrorMessageType : short { - //switch 998 cases in 3.5.0.3 - Invalid = -1, - NoErrorMessage = 0, - InternalError = 1, - NoPerm = 2, - NoInteractionAvailable = 3, - AlreadyInteractingSomeoneElse = 4, - NotNearToTarget = 5, - NoPermissionToLoot = 6, - CannotHarvestYet = 7, - WaterItemNeeded = 8, - LaborPowerNeeded = 9, - SeedItemNeeded = 10, - NeedToLearnInteraction = 11, - NeedItemToInteract = 12, - NeedQuestToInteract = 13, - InteractionRecoverParent = 14, - OnLootAction = 15, - LootItemCreate = 16, - FeedMax = 17, - InvalidTarget = 18, - AlreadyRequested = 19, - MoneyLocked = 20, - ItemLocked = 21, - ItemPickupLimit = 22, - ItemFailedRepair = 23, - ItemCannotUse = 24, - BagFull = 25, - NotEnoughMoney = 26, - NotEnoughItem = 27, - NotEnoughFriendship = 28, - NotEnoughLaborPower = 29, - ItemUpdateFail = 30, - FactionDuplicateName = 31, - FactionRights = 32, - FactionCreate = 33, - FactionCreateInvalidName = 34, - FactionCreateInSub = 35, - FactionCreateReportToBoss = 36, - FactionCreateOwner = 37, - FactionSeparate = 38, - FactionSeparateMother = 39, - FactionSeparateRights = 40, - FactionSubmit = 41, - FactionSubmitSelf = 42, - FactionSubmitChild = 43, - FactionSubmitMother = 44, - FactionSubmitRights = 45, - FactionDismiss = 46, - FactionDismissMother = 47, - FactionDismissRights = 48, - FactionInvite = 49, - FactionInviteOffline = 50, - FactionInviteRights = 51, - FactionInviteSelf = 52, - FactionInviteSame = 53, - FactionInviteOtherRights = 54, - FactionInviteOther = 55, - FactionInviteRejected = 56, - FactionJoin = 57, - FactionJoinNoInvitor = 58, - FactionLeave = 59, - FactionLeaveMother = 60, - FactionLeaveOwned = 61, - FactionKick = 62, - FactionKickMother = 63, - FactionKickRights = 64, - FactionKickSelf = 65, - FactionKickOwner = 66, - FactionKickNonMember = 67, - FactionKickOffline = 68, - FactionImmigrate = 69, - FactionChangeMemberRoleRights = 70, - TeamLoading = 71, - TeamNoRights = 72, - TeamFull = 73, - TeamFullOfficers = 74, - TeamInviteeMember = 75, - TeamInviteeOffline = 76, - TeamInviteeInTeam = 77, - TeamInvitorOffline = 78, - TeamInvitorMoved = 79, - TeamInviteRefused = 80, - TeamJoin = 81, - TeamJoinAlone = 82, - TeamNoSuchMember = 83, - TeamYourself = 84, - NotSpaceToSpawn = 85, - StoreUpdateInventory = 86, - StoreInvalidItem = 87, - StoreNotSellableItem = 88, - AuctionUpdateInventory = 89, - AuctionInvalidBidPrice = 90, - AuctionInvalidArticleForCancel = 91, - AuctionInvalidStartPrice = 92, - SlaveStart = 94, - SlaveCannotSpawn = 95, - SlaveCannotBind = 96, - SlaveAlreadyHasMaster = 97, - SlaveSpawnErrorDestroyed = 98, - SlaveSpawnErrorAlreadySpawned = 99, - SlaveSpawnShipNeedMoreSpace = 100, - SlaveSpawnItemLocked = 101, - SlaveUnbindFirst = 102, - SlaveShutOffToUnbind = 103, - SlaveEnd = 104, - MateCannotHire = 105, - MateCannotSpawnWhileCorpse = 106, - MateCannotMountBlocked = 107, - MateCannotSpawnNoSpace = 108, - MateCannotRepairWhileCorpse = 109, - MateDead = 110, - MateResurrected = 111, - HouseCannotLocateInvalidArea = 112, - HouseCannotLocateOverlapHouse = 113, - HouseCannotLocateOverlapUnit = 114, - HouseCannotLocateTerrainTooHigh = 115, - HouseCannotLocateTerrainTooLow = 116, - HouseCannotLocateConnectorMissed = 117, - HouseCannotLocateNotConnectedNeighbor = 118, - HouseCannotCreate = 119, - HouseCannotCreateLackMoney = 120, - HouseCannotSpawn = 121, - HouseCannotDecorate = 122, - HouseNotDecoratableState = 123, - HouseTooManyDecorations = 124, - HouseCannotDecorateOverlap = 125, - HouseCannotDecorateOutOfHouse = 126, - HouseCannotDecorateSurface = 127, - HouseCannotChangePermission = 128, - CraftAlreadyLearned = 129, - CraftNotLearned = 130, - CraftUpdaetInventory = 131, - CraftInteractionItemNotFound = 132, - CraftCooldown = 133, - CraftLimittimeOver = 134, - CraftPermissionDeny = 135, - CraftInvalidCraftType = 136, - CraftNotEnoughReposit = 137, - CraftMaterialRequired = 138, - CraftToolRequired = 139, - CraftInvalidAmount = 140, - CraftLocatingUnitIsNotExist = 141, - CraftLocatingUnitIsTooCloseToOther = 142, - CraftLocatingUnitIsTooCloseToUnit = 143, - CraftLocatingUnitIsNotOnTheWaterOrDeepWater = 144, - CraftCantLocateInInstant = 145, - CraftDesignItemIsNotValid = 146, - CraftDesignItemTypeIsNotValid = 147, - CraftCantActAnyMore = 148, - PriestAlreadyOwned = 149, - PriestCannotCreateBuff = 150, - TeleporterInvalidLocation = 151, - TooCloseOtherToClimb = 152, - TooFarAway = 154, - MailSuccess = 155, - MailNotEnoughMoney = 156, - MailTooMuchMoney = 157, - MailInvalidItem = 158, - MailNotFound = 159, - MailNoMoneyToTake = 160, - MailNoItemToTake = 161, - MailNotAllowedToReturn = 162, - MailTitleLengthLimited = 163, - MailTextLengthLimited = 164, - MailNotInitialized = 165, - MailInvalidFormat = 166, - MailInventoryUpdateFailed = 167, - MailCannotAccessToSelectedMail = 168, - MailUnknownFailure = 169, - MailItemLocked = 170, - MailWaitingForItemAction = 171, - MailInvalid = 172, - MailNoMoreAttachment = 173, - MailNoMoneyAttachedAtCurrentMail = 174, - MailReceiverNotFound = 175, - MailFailMailboxNotFound = 176, - MailFailSoulBoundItem = 177, - InteractionTargetNotNpc = 178, - InteractionNpcNotExists = 179, - InteractionNpcDescriptionNotFound = 180, - BagInvalidItem = 181, - BagItemDescriptionNotFound = 182, - StartPriceMoreThenZero = 183, - StartPriceInvalid = 185, - InvalidOptionOrNoResult = 187, - SearchFirst = 188, - NoNeedRequestToServerOrSearchAgain = 189, - SearchResultNotExistsOrLoaded = 190, - InvalidDepositOrMarketer = 191, - NoResultSearched = 192, - InvalidArticleForBidding = 193, - InvalidPriceForBidding = 194, - AuctionAccessAllowed = 195, - AuctionRefreshing = 196, - OptionInvalidOrNoResult = 197, - AuctionInitFailed = 198, - TooFarToDecorateHouse = 199, - NoMoreSpaceToDecorate = 200, - CannotMove = 201, - CannotChangeArmorInCombat = 202, - InvalidSlot = 203, - ItemNotForPet = 204, - ItemOnlyForPet = 205, - NotReady = 206, - FailedToUseItem = 207, - CannotEquipSlotIsLocked = 208, - CannotSetItemLook = 209, - ItemLookChanged = 210, - FailedToChangeItemLook = 211, - UnknownNpc = 212, - UnknownItem = 213, - UnknownSkill = 214, - InvalidLocation = 215, - TooManyCancel = 216, - BuyCartEmpty = 217, - SellCartEmpty = 218, - SoldListRefresh = 219, - NoGem = 220, - BagTarget = 221, - CannotInteractWhileMounting = 222, - CannotInteractWhileClimb = 223, - CannotRemoveSystemBuff = 224, - StoreNpcNotHandleThisItem = 225, - StoreItemDoesNotExist = 226, - StoreHaveProblem = 227, - StoreUnknownError = 228, - NoHousingArea = 229, - NoSuchUccExist = 230, - UpdateUccStringFailed = 231, - InteractionPermissionDeny = 232, - TradeIsNotPossibleInCombat = 233, - OnTrading = 234, - TargetOnTrading = 235, - NotOnTrading = 236, - OtherUnitIsNotExist = 237, - OtherIsNotWhoWas = 238, - ItemIsNotOn = 239, - CanNotPutupItem = 240, - CanNotPutupMoney = 241, - CanNotTakedownItem = 242, - TradeUpdate = 243, - CanNotOkWithOutLock = 244, - TradeInvalidItem = 245, - TradeOtherInvalidItem = 246, - TradeBagFull = 247, - TradeOtherBagFull = 248, - TradeNotEnoughMoney = 249, - TradeOtherNotEnoughMoney = 250, - TradeSoulBoundItem = 251, - InstanceInMsgStart = 252, - NoServerInstanceResource = 253, - TryLaterInstance = 254, - InstanceInMsgEnd = 255, - InvalidStateInstance = 256, - InvalidReturnPosInstance = 257, - ProhibitedInInstance = 258, - AlreadyUnboundInstance = 259, - InstantGameBadCorps = 260, - InstantGameBadRuleset = 261, - InstantGameBadApply = 262, - InstantGameReplyTimeout = 263, - YellTooOften = 264, - WhisperNoTarget = 265, - SaidForbiddenWord = 266, - ChatNotInParty = 267, - ChatNotInRaid = 268, - ChatChannelAlreadyExists = 269, - ChatNoChannel = 270, - ChatAlreadyJoinedChannel = 271, - ChatPrivateChannel = 272, - ChatWrongPassword = 273, - InvalidDoodadTarget = 274, - InvalidBoundDoodad = 275, - DoodadSimArea = 276, - DoodadSimTooCloseToOtherDoodad = 277, - DoodadSimTooCloseToOtherUnit = 278, - DoodadSimLowTerrain = 279, - DoodadSimNoError = 280, - EmblemNotApplicable = 281, - InvalidEmblemDownloadRequest = 282, - UpdateUcc = 283, - FindUccData = 284, - EmblemFileLoadFail = 285, - InstantGameBadLevel = 286, - ClosedZone = 287, - SlaveCannotRemoveWhileInCombat = 288, - HouseCannotDecorateOutOfGarden = 289, - HouseCannotDecorateInHouse = 290, - FactionChange = 291, - FactionChangeWrongId = 292, - ExpeditionCreateLevel = 293, - ExpeditionCreateMember = 294, - ExpeditionCreateMoney = 295, - ExpeditionNameCharacter = 296, - ExpeditionNameLength = 297, - ExpeditionNameBadlist = 298, - ExpeditionNameExist = 299, - ExpeditionMoneyLimit = 300, - ExpeditionOwnerDismiss = 301, - ExpeditionBadPassword = 302, - ExpeditionMemberLimit = 303, - ExpeditionBadFaction = 304, - ExpeditionInvitationDenial = 305, - ExpeditionOtherExpedition = 306, - ExpeditionBadStatus = 307, - ExpeditionOtherInvitation = 308, - ExpeditionNoTarget = 309, - ExpeditionOwnerCannotLeave = 310, - ChatNotInExpedition = 311, - SlaveDespawnNearTheSlave = 312, - PortalCountExceeded = 313, - NotEnoughHonorPoint = 314, - BackpackOccupied = 315, - ItemCannotMoveToBag = 316, - DominionAlreadyDedclared = 317, - DominionNotInExpedition = 318, - DominionMustHaveRelic = 319, - ExpeditionCreateMemberFaction = 320, - ExpeditionCreateFaction = 321, - NeedEquipBeforeUse = 322, - CantChangeEquip = 323, - SlaveCannotBindWhileIsDead = 324, - DoodadNotOnGround = 325, - MustEquipProperItem = 326, - ExpeditionChangeOwnerSelf = 327, - ExpeditionChangeOwnerMyExpedition = 328, - CofferInUse = 329, - ExpeditionCreateMemberExpedition = 330, - ItemCannotUseInBattleField = 331, - CantDoWhileYouDead = 332, - ExpeditionOwnerCannotDelete = 333, - CannotInteractWhileGliding = 334, - InstantGameServerCrash = 335, - CreateInvalidName = 336, - StoreCantBuyWithHonor = 337, - StoreCantBuyWithMoney = 338, - Backpack = 339, - HouseCannotLocateNotDominatedZone = 340, - HouseCannotLocateNearOthersGuardHouse = 341, - SiegeDeclareNoDominion = 342, - SiegeDeclareOwnZone = 343, - SiegeDeclareBadZone = 344, - SiegeDeclareTooNear = 345, - UccNoBg = 346, - UccNoFg = 347, - UccOnUpload = 348, - UccUploadFailed = 349, - InviteeInBattleField = 350, - DominionNotAvailableForPirates = 351, - CannotBlockUserSelf = 352, - BlockUser = 353, - UnblockUser = 354, - OtherBuildIsOn = 355, - CantDoOnDead = 356, - CannotUsePortalWithResurrectionBuff = 357, - CantDealWithHostileFaction = 358, - CannotPlaceMoreCoffer = 359, - CannotDuringSiegePeriod = 360, - StoreBackpackNogoods = 361, - FamilyInviteOffline = 362, - FamilyNoInvitor = 363, - FamilySelf = 364, - FamilyTitle = 365, - FamilyTitleBad = 366, - FamilyNoTarget = 367, - FamilyOtherFamily = 368, - FamilyHasFamily = 369, - FamilyNotOwner = 370, - FamilyAlready = 371, - FamilyMaximum = 372, - FamilyReject = 373, - FamilyCreate = 374, - FamilyRemoved = 375, - FamilyNotExist = 376, - CannotDemolishHouseWithTooManyCoffers = 377, - FamilyKickSelf = 378, - Family = 379, - HouseInvalidHeight = 380, - SlaveCannotRepairAlreadySpawned = 381, - SlaveRepaired = 382, - HouseUnderWaterOnly = 383, - HouseLandOnly = 384, - FamilyOwnerTitle = 385, - SiegeDeclareBadPeriod = 386, - AucInvalidTargetAuctioneer = 387, - AucAuctioneerTooFarAway = 388, - AucNotAuctioneer = 389, - AucInvalidItemOrNotInYourBag = 390, - AucRefreshDisplay = 391, - AucPermissionDeny = 392, - AucSoulBoundItem = 393, - AucNotRepairableItem = 394, - AucLowDurabilityItem = 395, - AucLowDeposit = 396, - AucLowStartMoney = 397, - AucWrongDirectMoney = 398, - AucInvalidSearchKeyword = 399, - AucBidMoneyUnderTopMost = 400, - AucBidMoneyUnderStartMoney = 401, - AucBidMoneyOverDirectMoney = 402, - AucDbArticleUpdate = 403, - AucDbCharCacheUpdate = 404, - AucDbItemUpdate = 405, - AucDbBidUpdate = 406, - DeleteCurrentReturnDistrict = 411, - ChatNotInFamily = 412, - CraftLowExpert = 413, - SlaveCannotRemoveWhileInCarryingBackpackDoodadItems = 417, - MailFailLifespanItem = 418, - AucLifespanItem = 419, - TradeItemAboutToExpire = 420, - ConsumeChangeNotSupport = 421, - AucNotSellable = 427, - AucBidSelf = 428, - CannotUseSiegeItem = 431, - TargetIsNotPlayer = 435, - NotEnoughSpace = 436, - ChatCannotWhisperToHostile = 437, - CannotUseInEquippedItem = 438, - NoReturnPoint = 439, - ItemCannotUseHere = 440, - TooManyOwnedDominions = 441, - SiegeDeclaredAlready = 442, - SiegeDeclaredAlreadyByOther = 443, - SiegeDeclarePirate = 444, - SiegeParticipantFull = 445, - SiegeNotParticipant = 446, - OpenPortalAtSiegeArea = 447, - SkillCannotUseInBattleField = 448, - SkillCannotUseHere = 449, - AucInternalError = 450, - AucServiceUnavailable = 451, - AucServerBusy = 452, - InstanceVisitLimit = 453, - AucMinimumStartPrice = 454, - AucInvalidEntry = 455, - SiegeBanPirate = 456, - SiegeBlockDefenseReinforce = 457, - SiegeWarPeriodOnly = 458, - SiegeMasterOnly = 459, - SiegeNoTicket = 460, - SiegePeriodMercenaryInSiegeAreaOnly = 461, - SiegeTicketPriceChanged = 462, - SiegeOnlyDefenseOrOffenseTicketAtOnce = 463, - SiegeOtherOnlyDefenseOrOffenseTicketAtOnce = 464, - SiegePeriodWarmupOnly = 465, - CannotUseInBattleField = 466, - ChatNotJoinedChannel = 467, - LevelLowToEquip = 468, - ExpeditionDismissInSiege = 469, - InstanceLevel = 470, - InstanceQuota = 471, - InstanceLeaveParty = 472, - InvalidTaxation = 473, - PrisonerCannotJoinBattleField = 474, - Trials = 477, - TrialsAlreadyClosed = 478, - TrialsJuryFull = 479, - TrialsClosedByDefendant = 480, - MailNotEnoughMoneyToPayTaxes = 481, - CartEmpty = 482, - NotEnoughCoin = 483, - TeleportToSiegeHq = 484, - TeleportToResurrectPos = 485, - TrialsDefendantDisconnected = 486, - TrialsClosedByDefendantDisconnect = 487, - TaxrateChangeLater = 488, - NotEnoughCommonfarmCapacity = 489, - CannotMoveSoulboundItemToCoffer = 490, - DismissIndunSuccessed = 491, - SlaveUccImprinted = 492, - CommonFarmCountOver = 493, - CommonFarmNotAllowedType = 494, - CannotFollowInCombat = 495, - ChatNotRaidOwner = 496, - CannotFollowNonParty = 497, - CannotFollowTooFar = 498, - MsgFollowingBegin = 499, - MsgFollowingEnd = 500, - CannotAddFriendSelf = 501, - AddFriend = 502, - DeleteFriend = 503, - BadDuelTarget = 504, - AlreadyInDuel = 505, - OtherAlreadyInDuel = 506, - TargetRejectedDuel = 507, - ActabilityNotEnoughPoint = 508, - ActabilityCanUpgradeAnyMore = 509, - ActabilityCanUpgradeSelectionCountLimit = 510, - ActabilityCanDowngradeAnyMore = 511, - StoreCantSellSameZone = 512, - BadDuelSelf = 513, - NotEnoughBankMoney = 514, - DuelOtherBusy = 515, - DuelBadLocation = 516, - TargetTooFar = 517, - LevelLowToUse = 518, - AucKeywordOrCategoryNeeded = 519, - AucInvalidLevelRange = 520, - AucBidNothingItem = 521, - FactionRelationSubjectNotFound = 522, - FactionRelationAlreadyHostile = 523, - FactionRelationAlreadyFriendly = 524, - FactionRelationProposalNotFound = 525, - FactionRelationProposalAlreadyExists = 526, - FactionRelationCannotChangeYet = 527, - FactionRelationCannotChangeWithSelf = 528, - FamilyAlreadyOwner = 529, - LevelHighToUse = 530, - LevelHighToEquip = 531, - QuestRewardedByMail = 532, - CastleCannotLocateInvalidArea = 533, - DiceRollInProgress = 534, - BlockedForFreeTrial = 535, - CannotTradeWithFreeTrial = 536, - CannotMoveLifespanItemIntoCoffer = 537, - TradeTargetIsNotPossibleState = 538, - CantTradeWithOtherView = 539, - SlaveSpawnErrorNeedRepairTime = 540, - AucMaxBids = 541, - AucMaxPosts = 542, - CannotChangeBackpackInGliding = 543, - CannotJoinTrialFromInstantZone = 544, - WhisperDisabled = 545, - AucCannotCancelIfBid = 546, - QuestMailSent = 547, - ExceedMaxDominionGateOrWall = 548, - TrialsCannotJoinAfterStart = 549, - Community = 550, - UserNotExist = 551, - UpdateUccSlaveExist = 552, - CannotAddExistingMember = 553, - CannotExitWhileInTrial = 554, - MailFailDisableArchebill = 555, - CannotFindInFriendList = 556, - CannotAcceptJuryInvitationWithBackpack = 557, - CannotDuelDuringForceAttack = 558, - CannotDuelDuringForceAttackOther = 559, - CannotForceAttackDuringDuel = 560, - InviteError = 561, - InviteConsideringOtherInvitation = 562, - InviteBadStatus = 563, - InviteNoGmTarget = 564, - CannotLocateDoodadNow = 565, - ExpeditionCannotJoinMemberFull = 566, - HouseCannotDemolishUnpaidTax = 567, - ExpeditionOwnerCannotChangeDuringSiege = 568, - CannotFindInView = 569, - BotReportAlreadyReportedByYou = 570, - BotReportAlreadyReportedByOther = 571, - CannotReportBot = 572, - BotReportExceededDailyLimit = 573, - CannotChangeEquipWhenDead = 574, - CannotDeleteCharWhileOnPlay = 575, - NoPortalBook = 576, - NotEnoughBloodyArchium = 577, - CannotRequestCommonfarmInfoInInstantZone = 578, - CannotDeleteCharWhilePenalty = 579, - HouseCannotLoacateInvalidCategoryArea = 580, - SiegeNoRightsInExpedition = 581, - DominionNotDeclareTime = 582, - SlaveSpawnErrorInvalidArea = 583, - CannotSetBountyForNotWanted = 584, - CannotSetBountyForSuchName = 585, - CannotSetBounty = 586, - AuctionUccPost = 587, - InvitationCanceledTimeout = 588, - IngameShopBuySuccess = 589, - IngameShopBuyFail = 590, - IngameShopNotEnoughAaCash = 591, - IngameShopNotEnoughAaPoint = 592, - IngameShopBuyGiftSuccess = 593, - IngameShopBuyGiftFail = 594, - IngameShopSoldOut = 595, - IngameShopExpiredSellByDate = 596, - UccLoading = 597, - UccLoadingEmblem = 598, - UccInvalidData = 599, - UccInvalidEmblem = 600, - UccInternalFileLoad = 601, - UccInternalTextureLoad = 602, - IngameShopBuyLowLevel = 603, - IngameShopBuyQuestIncomplete = 604, - SpecialtyNotBuyNow = 605, - QuestMailNotEnoughItems = 606, - HouseCannotCreateConstructTaxAbnormal = 607, - InvalidPortal = 608, - NotMyPortal = 609, - CannotUsePortalWithBackpack = 610, - CannotUsePortalInTrial = 611, - SoldBackpackRefundSentByMail = 612, - PermissionChanged = 613, - InvalidHouseInfo = 614, - HouseCannotOwnMoreHouselessCondition = 615, - HouseCannotOwnMoreExistingCategoryCondition = 616, - NotEnoughLivingPoint = 617, - MailDelayDemolishedHouseByUnpaidTax = 618, - SlaveSpawnErrorOffedZone = 619, - SlaveRemovedOffedZone = 620, - QuestDailyLimit = 621, - MailDelayDestroyedShipyard = 622, - IngameShopFindCharacterNameFail = 623, - CannotDeleteCharWhileBotSuspected = 624, - SiegeCannotDeclareNearResurrectPos = 625, - SpecialtyMargin = 626, - StoreCantBuyWithLivingPoint = 627, - HousingActabilityDecoLimited = 628, - AcatbilityDecoArrangFail = 629, - ArrestFailedDueToFullCourt = 630, - SpawnedSlaveExists = 631, - EnterInstReqItem = 632, - SiegeCannotDeclareNearHouse = 633, - BlockedForPromotionUser = 634, - ChTransferCannotBecomeExpeditionOwner = 635, - ChTransferCannotBuild = 636, - ChTransferCannotDeleteCharacter = 637, - ChTransferCannotPostOrBidAuction = 638, - SiegeAlreadyParticipating = 639, - SlaveEscapeTooFarFromSlave = 640, - MustEquipInstrumentItem = 641, - HouseCannotSellAsNotOwner = 642, - HouseCannotSellAsCastle = 643, - HouseCannotSellAsType = 644, - HouseCannotSellAsDelayedTax = 645, - HouseCannotSellAsAlreadyForSale = 646, - HouseCannotSellAsNotEnoughSeal = 647, - HouseCannotSellAsDesignatedBuyerNotFound = 648, - HouseCannotSellAsDbError = 649, - HouseCannotCancelSellAsNotOwner = 651, - HouseCannotCancelSellAsNotForSale = 652, - HouseCannotCancelSellAsDbError = 653, - HouseCannotBuyAsNotForSale = 654, - HouseCannotBuyAsOwner = 655, - HouseCannotBuyAsNotDesignatedBuyer = 656, - HouseCannotBuyAsNotEnoughMoney = 657, - HouseCannotBuyAsSaleInfoChanged = 658, - HouseCannotBuyAsDbError = 659, - CannotDecorateHouseDuringWar = 660, - SiegeCannotDeclareNearOtherZone = 661, - DominionClosed = 662, - AddCharacterSlotFail = 663, - ItemSecureCondition = 664, - GradeEnchantMax = 665, - HouseCannotSellAsUnderConstruction = 668, - CannotRechargeWhenEquipped = 669, - NoUsableExp = 670, - NeedParty = 671, - CannotForceAttackDuringBattleField = 672, - NoMatchGenderToEquip = 673, - UserMusicCannotPlayDueToDifficulty = 674, - RunawayCantApplyBattleField = 675, - MailPayChargeFirst = 676, - SpecialtyCoinMargin = 677, - InstantGameCannotJoinByBuff = 678, - InstantGameInvalidData = 679, - InstantGameCannotJoinByNoSeamless = 680, - HouseCannotSellToOneself = 681, - UserNoteCannotSave = 682, - IngameShopBuyNoDuplicateItem = 683, - DominionNationalTaxInvalidRate = 684, - DominionNationalTaxNoPermission = 685, - NotEnoughExpandItem = 686, - NotEnoughExpandItemAndMoney = 687, - SecondPassSettedMsg = 688, - NotEnoughBmMileage = 689, - ModifyBmMileage = 690, - ScheduleItemSent = 691, - CannotDyeingWhenEquipped = 692, - FactionCannotImmigrateAsGeneral = 693, - FactionCannotImmigrateAsPirate = 694, - FactionCannotInviteImmigrationAsNoPermission = 697, - AllEquipmentsAreSecured = 698, - AllEquipmentsAreUnsecured = 699, - ItemNotForUnderwaterCreature = 700, - ItemOnlyForUnderwaterCreature = 701, - ConnotUseWhileHaveMusicalBuffs = 702, - ExpeditionOwnerCannotEngraveGuardTower = 703, - FactionKickTargetNotFound = 704, - FactionKickOtherFaction = 705, - DemolishedHouseByExpiration = 706, - NotEnoughAaPoint = 707, - NotEnoughBankAaPoint = 708, - StoreCantBuyWithAaPoint = 709, - StoreCantBuyWithMoneyWithAaPoint = 710, - FactionOwnerCannotDelete = 711, - ChTransferHasMould = 712, - CraftNotHasMould = 713, - CraftAlreadyMould = 714, - CraftMouldNotFound = 715, - CraftMouldNotReady = 716, - InstantGameCannotLeave = 717, - FactionDiplomacyInvalidSubject = 718, - TransferChCannotEngrave = 720, - InviteEnterBeautyshop = 721, - NotEnoughRequiredItem = 722, - CannotEditGenderAndModelAsDbError = 723, - DominionNationalTaxLater = 725, - FactionKickExpeditionMember = 726, - MailReceiverToBeTransferred = 727, - FactionCannotImmigrateAsLevelLow = 728, - InstantGameCancelForOtherInstant = 729, - FactionCannotImmigrateToUserAsAlreadyMember = 730, - FactionCannotImmigrateToUserAsFactionOwner = 731, - FactionCannotImmigrateToUserAsExpeditionMember = 732, - FactionCannotImmigrateToOrigAsAlreadyMember = 733, - FactionCannotImmigrateToOrigAsFactionOwner = 734, - FactionCannotImmigrateToOrigAsExpeditionMember = 735, - FactionCannotImmigrationAsOneself = 736, - ItemLookConvertAsInvalidCombination = 737, - ItemLookConvertAsNotUseAsStat = 738, - ItemLookConvertAsNotUseAsSkin = 739, - Maintenance = 740, - SiegeCannotDeclareObstacle = 741, - ItemSocketsFull = 742, - ItemSocketsEmpty = 743, - GenderTransferAsGenderEquipment = 744, - SecondPassCheckOverFailed = 745, - RankInvalidData = 746, - RankCannotRequestDataTime = 747, - OnlyNationOwner = 748, - LocateInvalidDominionArea = 749, - NoMoreNationalMonument = 750, - CantPutUpNationalMonumentDuringSiegePeriod = 751, - StoreOneTimeSale = 752, - ItemLookConvertAsDiffGender = 753, - ItemPackCondition = 754, - UnlawfulCannotEngrave = 755, - CannotHangDuringTeleport = 756, - NationOwnerAtPosOnly = 757, - DominionOwnerAtPosOnly = 758, - AlreadyInNonPvpDuration = 759, - SiegeNearWarPeriod = 760, - ExpeditionAlreadyMember = 761, - ExpeditionNotBeginner = 762, - ExpeditionBeginnerNotFound = 763, - ExpeditionBeginnerFull = 764, - ExpeditionBeginnerCannotJoinAsInvalidFaction = 765, - HouseCannotConstructInAreaByMaxConstructCount = 766, - SlaveEquipmentNoBuff = 767, - SlaveEquipmentNotOwner = 768, - RankRewardSent = 769, - FactionCannotImmigrateAsCombat = 770, - AucPostBlocked = 771, - PremiumServiceBuySuccess = 772, - PremiumServiceBuyFail = 773, - PremiumServiceNotEnoughAaCash = 774, - PremiumServiceNotEnoughAaPoint = 775, - CanNotOnMovingPhysicalVehicle = 776, - RankInvalidBigFishData = 777, - IngameShopBuyFailAaPoint = 778, - IngameShopFindCharacterSameAccount = 779, - IngameShopLimitedBuyForTotalPrice = 780, - SocketTargetLevel = 781, - IngameShopNeedCheckSecondPassword = 782, - FactionInviteBattlefield = 783, - IngameShopNotEnoughBmMileage = 784, - MailCannotSendSinceLevelLow = 785, - ChatCannotSendSinceLevelLow = 786, - BuffHigher = 787, - AlreadyGenderTransfered = 788, - IngameShopBuyFailInvalidAccount = 789, - IngameShopChracterDeleteRequested = 790, - IngameShopChracterTransferRequested = 791, - RankNoOngoingRanks = 792, - CannotReusePortalInDelayTime = 793, - NotPlaySensitiveOperation = 794, - AchievementItemSent = 795, - CannotRecoverAllNotEnough = 796, - CannotRecoverAllLevelUp = 797, - MailCoolTime = 798, - MailRepetition = 799, - SlaveEquipmentLoadedItem = 800, - ChTransferCannotImmigrate = 801, - CannotAutoRegisterSkill = 802, - SlaveEquipErrorRequireSlotAndItem = 803, - SlaveUnequipErrorUnequipFirst = 804, - AucInvalidPostAuthority = 805, - CanNotUseSystemHotKey = 806, - OnlyExpeditionOwner = 807, - OnlyExpeditionMember = 808, - // added in 3.0.3.0 - RevertInvalidItemLook = 809, - TradeLockDelay = 810, - HouseCannotPrepayForSale = 811, - HouseCannotPrepayUnpaidTax = 812, - HouseCannotPrepayUnderConstruction = 813, - HouseCannotPrepayAnyMore = 814, - HouseCannotSellAsPrepaidTax = 815, - QuestToday = 816, - SlaveEquipmentNotToggled = 817, - FactionInviteRestrictionTime = 818, - QuestItemCannotInsertIntoCoffer = 819, - NotAcceptableItemCategoryTypeForPrivateCoffer = 820, - CannotRideBackpacker = 821, - SlaveOverSpeed = 822, - NotSupportedGraphicCard = 823, - NotSupportedGraphicCardD3dtexturecapsPow2 = 824, - NotEnoughGraphicMemory = 825, - NotEnoughShaderVersion = 826, - NotEnoughDesktopResolution = 827, - InvalidRepairAuthorityInBag = 828, - SlaveAndMateCannotIntoBankOrCoffer = 829, - ChTransferCannotBuyHouse = 830, - AucPostAlreadyAuthority = 831, - AucPostNonAuthority = 832, - MailFailLevelLimited = 833, - ImpossibleDeadState = 834, - ImpossibleCombatState = 835, - InstanceInvalidEnter = 836, - InstanceEnterCount = 837, - InstanceTicket = 838, - MailFailRestrictOwnerChange = 839, - FailedEnterInstanceBecauseSlave = 840, - ChatNotInTrial = 841, - OverAaPointMaxLimit = 842, - WorldRestrictOwnerChange = 843, - InstantGameCannotJoinByBotChecking = 844, - InstantGameCannotJoinByTrade = 845, - NotTeleportCombat = 846, - NotTeleportDead = 847, - NotEnoughEmptySlotsInBag = 848, - NoPermissionOpenPortal = 849, - IssuanceOfMobilizationOrderHeroOnly = 850, - IssuanceOfMobilizationOrderNotMyDominion = 851, - NotExistReturnPoint = 852, - WrongLeadershipPoint = 853, - WrongHero = 854, - TimeoutAndCancel = 855, - OngoingHandOverOwner = 856, - NotHeroAbstainPeriod = 857, - NotHeroVotingPeriod = 858, - NotHeroAbstainVotingPeriod = 859, - NotHeroCandidate = 860, - NotHeroVoterCondition = 861, - EmptyHeroCandidates = 862, - UnfinishedBuildHouse = 863, - IssuanceOfMobilizationOrderNoNation = 864, - HousingAreaNotActivated = 865, - PingLineOverCount = 866, - DeleteRepresentCharacter = 867, - TodayAssignmentItemSent = 868, - AllOfEntryRondomUnitAttributesAlreadyExists = 869, - EntryRandomUnitAttributesDoNotExist = 870, - FailedToAddRandomUnitAttributes = 871, - StoreCantBuyWithContributionPoint = 872, - NotEnoughContributionPoint = 873, - NotEnoughExpeditionLevel = 874, - AucInvalidHudAuthority = 875, - AccountAttendanceAlreadyChecked = 876, - BagFullAndSentByMail = 877, - ExpeditionNotFound = 878, - ExpeditionInvalidExp = 879, - ExpeditionCannotLevelUp = 880, - ExpeditionProgressLevelUp = 881, - TargetExpeditionIsUnderProtection = 882, - TargetExpeditionIsLowLevel = 883, - TargetExpeditionGearScore = 884, - TargetExpeditionIsInWar = 885, - ExpeditionIsInUnderProtection = 886, - ExpeditionIsLowLevel = 887, - ExpeditionCannotJoinDuringWar = 888, - IssuanceOfMobilizationOrderCountMax = 889, - OnlyDominionExpeditionMember = 890, - MailFailReportedSpamMail = 891, - SummonFail = 892, - SummonNotEnoughSpace = 893, - SummonCancelNotMove = 894, - ImpossibleMove = 895, - ExpeditionOwnerChangeTooOften = 896, - TeamInviteeInBattleField = 897, - TeamInvitorInBattleField = 898, - ExpeditionCreateApplicant = 899, - DeleteCharacterFailScheduleItemSelCharLock = 900, - ExpeditionSummonNotInstant = 901, - ExpeditionApplicantLimitCount = 902, - ExpeditionSummonNotLeave = 903, - InvalidHudBattlefieldAuthority = 904, - CanNotUseItemSkillByWorldRestriction = 905, - ExpeditionBlockedWord = 906, - OnlyDominionNationMember = 907, - ExpeditionMobilizationBuff = 908, - ExpeditionDismissDuringChanneling = 909, - MateSpawnErrorDead = 910, - DisableTwoToneHair = 911, - BuffCannotUseInBattleField = 912, - CanNotLearnSkillInPreviewMode = 913, - HousingAreaNotOpen = 914, - CannotUseSiegeSkill = 915, - AlreadySavedSkillSet = 916, - CannotMoveItemToCoffer = 917, - HousePackageDemolishFailedNotEnoughSeal = 918, - HousePackageDemolishFailedUnderConstruction = 919, - CannotDeleteHasComercialMailItem = 920, - IngameShopCannotUseAacoinForGift = 921, - CreateExpeditionRejoinError = 922, - NationMemberLimitJoin = 923, - NationMemberLimitInvite = 924, - ExceedMaxDominionKeep = 925, - InZoneGroupHousingExist = 926, - InZoneGroupHousingNotExist = 927, - InstanceMatchingFailed = 928, - ExpeditionLevelNotMatch = 929, - ExceedMaxDominionBuilding = 930, - HousingNoAssetDiagonal = 931, - ChangeNationOwnerToHero = 932, - ChangeNationOwnerToSelf = 933, - ChangeNationOwnerToNotNational = 934, - ChangeNationOwnerToChTransfer = 935, - ChangeNationOwnerTooOften = 936, - AlreadyRelationHostile = 937, - InstanceGmEventEnded = 938, - InstanceGmEventFailure = 939, - NotRelationVoteParticipation = 940, - CannotRideWithBackpack = 941, - CanRenameExpeditionOwner = 942, - RenameExpeditionMayBePossibleAfterThirtiethDays = 943, - TargetBagIsFull = 944, - TradeBan = 945, - ItemLookConvertAsNotUseAsExtract = 946, - ReputationBadZone = 947, - ReputationTargetLevelLow = 948, - ReputationOwnerLevelLow = 949, - ReputationOwnerLeadershipLow = 950, - ReputationIsMe = 951, - ReputationNotSameTeam = 952, - ReputationNotSameFaction = 953, - ReputationNotTime = 954, - ImmigrationExpeditonMemberOver = 955, - ImmigrationExpeditonFull = 956, - ImmigrationExpeditonNotPirate = 957, - ImmigrationExpeditonLimitLevel = 958, - ImmigrationExpeditonNotEnoughOwnerLevel = 959, - ImmigrationExpeditonNotChangeOwner = 960, - CannotRide = 961, - NonResident = 962, - NeedMoreResidentServicePoint = 963, - IntensifiedExpertDowngradeNeedItem = 964, - ChatCannotSendByBuff = 965, - CannotTarget = 966, - CannotChangeTarget = 967, - RemoveHighAbilityLevelLimit = 968, - NuonsArrowTargetNotSelected = 969, - NuonsArrowTargetInvalid = 970, - NotChangeFamilyRoleTime = 973, - NotJoinFamily = 974, - BackpackOneByOne = 975, - FamilyRoleNotMatch = 976, - ImmigrationExpeditonNotAccpet = 977, - FamilyNameInvalid = 978, - FamilyNameBad = 979, - NationImmigrationApplyCountMax = 980, - //// Added in 3.5 - //IngameShopTimeout = 981, - //FriendNameInvalid = 982, - //BlockNameInvalid = 983, - //ExpeditionNameInvalid = 984, - //NationNameInvalid = 985, - //CannotForceAttack = 986, - //TradegoodsStockLimitExceed = 987, - //NotEnoughAbilityLevel = 988, - //ConditionNotMatch = 989, - //SpecialtyStockFull = 990, - //TradegoodNotPassedTradepost = 991, - //TradegoodsStockEmpty = 992, - //HeirExpFull = 993, - //CannotFollow = 994, - //NotEnoughItemType = 995, - //UseItemType = 996, - //InvalidSlaveFollowCondition = 997 + // updated to version 5.0.7.0 + Invalid = -1, // invalid + NoErrorMessage = 0, // no_error_message + InternalError = 1, // internal_error + NoPerm = 2, // no_perm + NoInteractionAvailable = 3, // no_interaction_available + AlreadyInteractingSomeoneElse = 4, // already_interacting_someone_else + NotNearToTarget = 5, // not_near_to_target + NoPermissionToLoot = 6, // no_permission_to_loot + CannotHarvestYet = 7, // cannot_harvest_yet + WaterItemNeeded = 8, // water_item_needed + LaborPowerNeeded = 9, // labor_power_needed + SeedItemNeeded = 10, // seed_item_needed + NeedToLearnInteraction = 11, // need_to_learn_interaction + NeedItemToInteract = 12, // need_item_to_interact + NeedQuestToInteract = 13, // need_quest_to_interact + InteractionRecoverParent = 14, // interaction_recover_parent + OnLootAction = 15, // on_loot_action + LootItemCreate = 16, // loot_item_create + FeedMax = 17, // feed_max + InvalidTarget = 18, // invalid_target + AlreadyRequested = 19, // already_requested + MoneyLocked = 20, // money_locked + ItemLocked = 21, // item_locked + ItemPickupLimit = 22, // item_pickup_limit + ItemFailedRepair = 23, // item_failed_repair + ItemCannotUse = 24, // item_cannot_use + BagFull = 25, // bag_full + NotEnoughMoney = 26, // not_enough_money + NotEnoughItem = 27, // not_enough_item + NotEnoughFriendship = 28, // not_enough_friendship + NotEnoughLaborPower = 29, // not_enough_labor_power + ItemUpdateFail = 30, // item_update_fail + FactionDuplicateName = 31, // faction_duplicate_name + FactionRights = 32, // faction_rights + FactionCreate = 33, // faction_create + FactionCreateInvalidName = 34, // faction_create_invalid_name + FactionCreateInSub = 35, // faction_create_in_sub + FactionCreateReportToBoss = 36, // faction_create_report_to_boss + FactionCreateOwner = 37, // faction_create_owner + FactionSeparate = 38, // faction_separate + FactionSeparateMother = 39, // faction_separate_mother + FactionSeparateRights = 40, // faction_separate_rights + FactionSubmit = 41, // faction_submit + FactionSubmitSelf = 42, // faction_submit_self + FactionSubmitChild = 43, // faction_submit_child + FactionSubmitMother = 44, // faction_submit_mother + FactionSubmitRights = 45, // faction_submit_rights + FactionDismiss = 46, // faction_dismiss + FactionDismissMother = 47, // faction_dismiss_mother + FactionDismissRights = 48, // faction_dismiss_rights + FactionInvite = 49, // faction_invite + FactionInviteOffline = 50, // faction_invite_offline + FactionInviteRights = 51, // faction_invite_rights + FactionInviteSelf = 52, // faction_invite_self + FactionInviteSame = 53, // faction_invite_same + FactionInviteOtherRights = 54, // faction_invite_other_rights + FactionInviteOther = 55, // faction_invite_other + FactionInviteRejected = 56, // faction_invite_rejected + FactionJoin = 57, // faction_join + FactionJoinNoInvitor = 58, // faction_join_no_invitor + FactionLeave = 59, // faction_leave + FactionLeaveMother = 60, // faction_leave_mother + FactionLeaveOwned = 61, // faction_leave_owned + FactionKick = 62, // faction_kick + FactionKickMother = 63, // faction_kick_mother + FactionKickRights = 64, // faction_kick_rights + FactionKickSelf = 65, // faction_kick_self + FactionKickOwner = 66, // faction_kick_owner + FactionKickNonMember = 67, // faction_kick_non_member + FactionKickOffline = 68, // faction_kick_offline + FactionImmigrate = 69, // faction_immigrate + FactionChangeMemberRoleRights = 70, // faction_change_member_role_rights + TeamLoading = 71, // team_loading + TeamNoRights = 72, // team_no_rights + TeamFull = 73, // team_full + TeamFullOfficers = 74, // team_full_officers + TeamInviteeMember = 75, // team_invitee_member + TeamInviteeOffline = 76, // team_invitee_offline + TeamInviteeInTeam = 77, // team_invitee_in_team + TeamInvitorOffline = 78, // team_invitor_offline + TeamInvitorMoved = 79, // team_invitor_moved + TeamInviteRefused = 80, // team_invite_refused + TeamJoin = 81, // team_join + TeamJoinAlone = 82, // team_join_alone + TeamNoSuchMember = 83, // team_no_such_member + TeamYourself = 84, // team_yourself + NotSpaceToSpawn = 85, // not_space_to_spawn + StoreUpdateInventory = 86, // store_update_inventory + StoreInvalidItem = 87, // store_invalid_item + StoreNotSellableItem = 88, // store_not_sellable_item + AuctionUpdateInventory = 89, // auction_update_inventory + AuctionInvalidBidPrice = 90, // auction_invalid_bid_price + AuctionInvalidArticleForCancel = 91, // auction_invalid_article_for_cancel + AuctionInvalidStartPrice = 92, // auction_invalid_start_price + SlaveStart = 94, // slave_start + SlaveCannotSpawn = 95, // slave_cannot_spawn + SlaveCannotBind = 96, // slave_cannot_bind + SlaveAlreadyHasMaster = 97, // slave_already_has_master + SlaveSpawnErrorDestroyed = 98, // slave_spawn_error_destroyed + SlaveSpawnErrorAlreadySpawned = 99, // slave_spawn_error_already_spawned + SlaveSpawnShipNeedMoreSpace = 100, // slave_spawn_ship_need_more_space + SlaveSpawnItemLocked = 101, // slave_spawn_item_locked + SlaveUnbindFirst = 102, // slave_unbind_first + SlaveShutOffToUnbind = 103, // slave_shut_off_to_unbind + SlaveEnd = 104, // slave_end + MateCannotHire = 105, // mate_cannot_hire + MateCannotSpawnWhileCorpse = 106, // mate_cannot_spawn_while_corpse + MateCannotMountBlocked = 107, // mate_cannot_mount_blocked + MateCannotSpawnNoSpace = 108, // mate_cannot_spawn_no_space + MateCannotRepairWhileCorpse = 109, // mate_cannot_repair_while_corpse + MateDead = 110, // mate_dead + MateResurrected = 111, // mate_resurrected + HouseCannotLocateInvalidArea = 112, // house_cannot_locate_invalid_area + HouseCannotLocateOverlapHouse = 113, // house_cannot_locate_overlap_house + HouseCannotLocateOverlapUnit = 114, // house_cannot_locate_overlap_unit + HouseCannotLocateTerrainTooHigh = 115, // house_cannot_locate_terrain_too_high + HouseCannotLocateTerrainTooLow = 116, // house_cannot_locate_terrain_too_low + HouseCannotLocateConnectorMissed = 117, // house_cannot_locate_connector_missed + HouseCannotLocateNotConnectedNeighbor = 118, // house_cannot_locate_not_connected_neighbor + HouseCannotCreate = 119, // house_cannot_create + HouseCannotCreateLackMoney = 120, // house_cannot_create_lack_money + HouseCannotSpawn = 121, // house_cannot_spawn + HouseCannotDecorate = 122, // house_cannot_decorate + HouseNotDecoratableState = 123, // house_not_decoratable_state + HouseTooManyDecorations = 124, // house_too_many_decorations + HouseCannotDecorateOverlap = 125, // house_cannot_decorate_overlap + HouseCannotDecorateOutOfHouse = 126, // house_cannot_decorate_out_of_house + HouseCannotDecorateSurface = 127, // house_cannot_decorate_surface + HouseCannotChangePermission = 128, // house_cannot_change_permission + CraftAlreadyLearned = 129, // craft_already_learned + CraftNotLearned = 130, // craft_not_learned + CraftUpdaetInventory = 131, // craft_updaet_inventory + CraftInteractionItemNotFound = 132, // craft_interaction_item_not_found + CraftCooldown = 133, // craft_cooldown + CraftLimittimeOver = 134, // craft_limittime_over + CraftPermissionDeny = 135, // craft_permission_deny + CraftInvalidCraftType = 136, // craft_invalid_craft_type + CraftNotEnoughReposit = 137, // craft_not_enough_reposit + CraftMaterialRequired = 138, // craft_material_required + CraftToolRequired = 139, // craft_tool_required + CraftInvalidAmount = 140, // craft_invalid_amount + CraftLocatingUnitIsNotExist = 141, // craft_locating_unit_is_not_exist + CraftLocatingUnitIsTooCloseToOther = 142, // craft_locating_unit_is_too_close_to_other + CraftLocatingUnitIsTooCloseToUnit = 143, // craft_locating_unit_is_too_close_to_unit + CraftLocatingUnitIsNotOnTheWaterOrDeepWater = 144, // craft_locating_unit_is_not_on_the_water_or_deep_water + CraftCantLocateInInstant = 145, // craft_cant_locate_in_instant + CraftDesignItemIsNotValid = 146, // craft_design_item_is_not_valid + CraftDesignItemTypeIsNotValid = 147, // craft_design_item_type_is_not_valid + CraftCantActAnyMore = 148, // craft_cant_act_any_more + PriestAlreadyOwned = 149, // priest_already_owned + PriestCannotCreateBuff = 150, // priest_cannot_create_buff + TeleporterInvalidLocation = 151, // teleporter_invalid_location + TooCloseOtherToClimb = 152, // too_close_other_to_climb + TooFarAway = 154, // too_far_away + MailSuccess = 155, // mail_success + MailNotEnoughMoney = 156, // mail_not_enough_money + MailTooMuchMoney = 157, // mail_too_much_money + MailInvalidItem = 158, // mail_invalid_item + MailNotFound = 159, // mail_not_found + MailNoMoneyToTake = 160, // mail_no_money_to_take + MailNoItemToTake = 161, // mail_no_item_to_take + MailNotAllowedToReturn = 162, // mail_not_allowed_to_return + MailTitleLengthLimited = 163, // mail_title_length_limited + MailTextLengthLimited = 164, // mail_text_length_limited + MailNotInitialized = 165, // mail_not_initialized + MailInvalidFormat = 166, // mail_invalid_format + MailInventoryUpdateFailed = 167, // mail_inventory_update_failed + MailCannotAccessToSelectedMail = 168, // mail_cannot_access_to_selected_mail + MailUnknownFailure = 169, // mail_unknown_failure + MailItemLocked = 170, // mail_item_locked + MailWaitingForItemAction = 171, // mail_waiting_for_item_action + MailInvalid = 172, // mail_invalid + MailNoMoreAttachment = 173, // mail_no_more_attachment + MailNoMoneyAttachedAtCurrentMail = 174, // mail_no_money_attached_at_current_mail + MailReceiverNotFound = 175, // mail_receiver_not_found + MailFailMailboxNotFound = 176, // mail_fail_mailbox_not_found + MailFailSoulBoundItem = 177, // mail_fail_soul_bound_item + InteractionTargetNotNpc = 178, // interaction_target_not_npc + InteractionNpcNotExists = 179, // interaction_npc_not_exists + InteractionNpcDescriptionNotFound = 180, // interaction_npc_description_not_found + BagInvalidItem = 181, // bag_invalid_item + BagItemDescriptionNotFound = 182, // bag_item_description_not_found + StartPriceMoreThenZero = 183, // start_price_more_then_zero + StartPriceInvalid = 185, // start_price_invalid + InvalidOptionOrNoResult = 187, // invalid_option_or_no_result + SearchFirst = 188, // search_first + NoNeedRequestToServerOrSearchAgain = 189, // no_need_request_to_server_or_search_again + SearchResultNotExistsOrLoaded = 190, // search_result_not_exists_or_loaded + InvalidDepositOrMarketer = 191, // invalid_deposit_or_marketer + NoResultSearched = 192, // no_result_searched + InvalidArticleForBidding = 193, // invalid_article_for_bidding + InvalidPriceForBidding = 194, // invalid_price_for_bidding + AuctionAccessAllowed = 195, // auction_access_allowed + AuctionRefreshing = 196, // auction_refreshing + OptionInvalidOrNoResult = 197, // option_invalid_or_no_result + AuctionInitFailed = 198, // auction_init_failed + TooFarToDecorateHouse = 199, // too_far_to_decorate_house + NoMoreSpaceToDecorate = 200, // no_more_space_to_decorate + CannotMove = 201, // cannot_move + CannotChangeArmorInCombat = 202, // cannot_change_armor_in_combat + InvalidSlot = 203, // invalid_slot + ItemNotForPet = 204, // item_not_for_pet + ItemOnlyForPet = 205, // item_only_for_pet + NotReady = 206, // not_ready + FailedToUseItem = 207, // failed_to_use_item + CannotEquipSlotIsLocked = 208, // cannot_equip_slot_is_locked + CannotSetItemLook = 209, // cannot_set_item_look + ItemLookChanged = 210, // item_look_changed + FailedToChangeItemLook = 211, // failed_to_change_item_look + UnknownNpc = 212, // unknown_npc + UnknownItem = 213, // unknown_item + UnknownSkill = 214, // unknown_skill + InvalidLocation = 215, // invalid_location + TooManyCancel = 216, // too_many_cancel + BuyCartEmpty = 217, // buy_cart_empty + SellCartEmpty = 218, // sell_cart_empty + SoldListRefresh = 219, // sold_list_refresh + NoGem = 220, // no_gem + BagTarget = 221, // bag_target + CannotInteractWhileMounting = 222, // cannot_interact_while_mounting + CannotInteractWhileClimb = 223, // cannot_interact_while_climb + CannotRemoveSystemBuff = 224, // cannot_remove_system_buff + StoreNpcNotHandleThisItem = 225, // store_npc_not_handle_this_item + StoreItemDoesNotExist = 226, // store_item_does_not_exist + StoreHaveProblem = 227, // store_have_problem + StoreUnknownError = 228, // store_unknown_error + NoHousingArea = 229, // no_housing_area + NoSuchUccExist = 230, // no_such_ucc_exist + UpdateUccStringFailed = 231, // update_ucc_string_failed + InteractionPermissionDeny = 232, // interaction_permission_deny + TradeIsNotPossibleInCombat = 233, // trade_is_not_possible_in_combat + OnTrading = 234, // on_trading + TargetOnTrading = 235, // target_on_trading + NotOnTrading = 236, // not_on_trading + OtherUnitIsNotExist = 237, // other_unit_is_not_exist + OtherIsNotWhoWas = 238, // other_is_not_who_was + ItemIsNotOn = 239, // item_is_not_on + CanNotPutupItem = 240, // can_not_putup_item + CanNotPutupMoney = 241, // can_not_putup_money + CanNotTakedownItem = 242, // can_not_takedown_item + TradeUpdate = 243, // trade_update + CanNotOkWithOutLock = 244, // can_not_ok_with_out_lock + TradeInvalidItem = 245, // trade_invalid_item + TradeOtherInvalidItem = 246, // trade_other_invalid_item + TradeBagFull = 247, // trade_bag_full + TradeOtherBagFull = 248, // trade_other_bag_full + TradeNotEnoughMoney = 249, // trade_not_enough_money + TradeOtherNotEnoughMoney = 250, // trade_other_not_enough_money + TradeSoulBoundItem = 251, // trade_soul_bound_item + InstanceInMsgStart = 252, // instance_in_msg_start + NoServerInstanceResource = 253, // no_server_instance_resource + TryLaterInstance = 254, // try_later_instance + InstanceInMsgEnd = 255, // instance_in_msg_end + InvalidStateInstance = 256, // invalid_state_instance + InvalidReturnPosInstance = 257, // invalid_return_pos_instance + ProhibitedInInstance = 258, // prohibited_in_instance + AlreadyUnboundInstance = 259, // already_unbound_instance + InstantGameBadCorps = 260, // instant_game_bad_corps + InstantGameBadRuleset = 261, // instant_game_bad_ruleset + InstantGameBadApply = 262, // instant_game_bad_apply + InstantGameReplyTimeout = 263, // instant_game_reply_timeout + YellTooOften = 264, // yell_too_often + WhisperNoTarget = 265, // whisper_no_target + SaidForbiddenWord = 266, // said_forbidden_word + ChatNotInParty = 267, // chat_not_in_party + ChatNotInRaid = 268, // chat_not_in_raid + ChatChannelAlreadyExists = 269, // chat_channel_already_exists + ChatNoChannel = 270, // chat_no_channel + ChatAlreadyJoinedChannel = 271, // chat_already_joined_channel + ChatPrivateChannel = 272, // chat_private_channel + ChatWrongPassword = 273, // chat_wrong_password + InvalidDoodadTarget = 274, // invalid_doodad_target + InvalidBoundDoodad = 275, // invalid_bound_doodad + DoodadSimArea = 276, // doodad_sim_area + DoodadSimTooCloseToOtherDoodad = 277, // doodad_sim_too_close_to_other_doodad + DoodadSimTooCloseToOtherUnit = 278, // doodad_sim_too_close_to_other_unit + DoodadSimLowTerrain = 279, // doodad_sim_low_terrain + DoodadSimNoError = 280, // doodad_sim_no_error + EmblemNotApplicable = 281, // emblem_not_applicable + InvalidEmblemDownloadRequest = 282, // invalid_emblem_download_request + UpdateUcc = 283, // update_ucc + FindUccData = 284, // find_ucc_data + EmblemFileLoadFail = 285, // emblem_file_load_fail + InstantGameBadLevel = 286, // instant_game_bad_level + ClosedZone = 287, // closed_zone + SlaveCannotRemoveWhileInCombat = 288, // slave_cannot_remove_while_in_combat + HouseCannotDecorateOutOfGarden = 289, // house_cannot_decorate_out_of_garden + HouseCannotDecorateInHouse = 290, // house_cannot_decorate_in_house + FactionChange = 291, // faction_change + FactionChangeWrongId = 292, // faction_change_wrong_id + ExpeditionCreateLevel = 293, // expedition_create_level + ExpeditionCreateMember = 294, // expedition_create_member + ExpeditionCreateMoney = 295, // expedition_create_money + ExpeditionNameCharacter = 296, // expedition_name_character + ExpeditionNameLength = 297, // expedition_name_length + ExpeditionNameBadlist = 298, // expedition_name_badlist + ExpeditionNameExist = 299, // expedition_name_exist + ExpeditionMoneyLimit = 300, // expedition_money_limit + ExpeditionOwnerDismiss = 301, // expedition_owner_dismiss + ExpeditionBadPassword = 302, // expedition_bad_password + ExpeditionMemberLimit = 303, // expedition_member_limit + ExpeditionBadFaction = 304, // expedition_bad_faction + ExpeditionInvitationDenial = 305, // expedition_invitation_denial + ExpeditionOtherExpedition = 306, // expedition_other_expedition + ExpeditionBadStatus = 307, // expedition_bad_status + ExpeditionOtherInvitation = 308, // expedition_other_invitation + ExpeditionNoTarget = 309, // expedition_no_target + ExpeditionOwnerCannotLeave = 310, // expedition_owner_cannot_leave + ChatNotInExpedition = 311, // chat_not_in_expedition + SlaveDespawnNearTheSlave = 312, // slave_despawn_near_the_slave + PortalCountExceeded = 313, // portal_count_exceeded + NotEnoughHonorPoint = 314, // not_enough_honor_point + BackpackOccupied = 315, // backpack_occupied + ItemCannotMoveToBag = 316, // item_cannot_move_to_bag + DominionAlreadyDedclared = 317, // dominion_already_dedclared + DominionNotInExpedition = 318, // dominion_not_in_expedition + DominionMustHaveRelic = 319, // dominion_must_have_relic + ExpeditionCreateMemberFaction = 320, // expedition_create_member_faction + ExpeditionCreateFaction = 321, // expedition_create_faction + NeedEquipBeforeUse = 322, // need_equip_before_use + CantChangeEquip = 323, // cant_change_equip + SlaveCannotBindWhileIsDead = 324, // slave_cannot_bind_while_is_dead + DoodadNotOnGround = 325, // doodad_not_on_ground + MustEquipProperItem = 326, // must_equip_proper_item + ExpeditionChangeOwnerSelf = 327, // expedition_change_owner_self + ExpeditionChangeOwnerMyExpedition = 328, // expedition_change_owner_my_expedition + CofferInUse = 329, // coffer_in_use + ExpeditionCreateMemberExpedition = 330, // expedition_create_member_expedition + ItemCannotUseInBattleField = 331, // item_cannot_use_in_battle_field + CantDoWhileYouDead = 332, // cant_do_while_you_dead + ExpeditionOwnerCannotDelete = 333, // expedition_owner_cannot_delete + CannotInteractWhileGliding = 334, // cannot_interact_while_gliding + InstantGameServerCrash = 335, // instant_game_server_crash + CreateInvalidName = 336, // create_invalid_name + StoreCantBuyWithHonor = 337, // store_cant_buy_with_honor + StoreCantBuyWithMoney = 338, // store_cant_buy_with_money + Backpack = 339, // backpack + HouseCannotLocateNotDominatedZone = 340, // house_cannot_locate_not_dominated_zone + HouseCannotLocateNearOthersGuardHouse = 341, // house_cannot_locate_near_others_guard_house + SiegeDeclareNoDominion = 342, // siege_declare_no_dominion + SiegeDeclareOwnZone = 343, // siege_declare_own_zone + SiegeDeclareBadZone = 344, // siege_declare_bad_zone + SiegeDeclareTooNear = 345, // siege_declare_too_near + UccNoBg = 346, // ucc_no_bg + UccNoFg = 347, // ucc_no_fg + UccOnUpload = 348, // ucc_on_upload + UccUploadFailed = 349, // ucc_upload_failed + InviteeInBattleField = 350, // invitee_in_battle_field + DominionNotAvailableForPirates = 351, // dominion_not_available_for_pirates + CannotBlockUserSelf = 352, // cannot_block_user_self + BlockUser = 353, // block_user + UnblockUser = 354, // unblock_user + OtherBuildIsOn = 355, // other_build_is_on + CantDoOnDead = 356, // cant_do_on_dead + CannotUsePortalWithResurrectionBuff = 357, // cannot_use_portal_with_resurrection_buff + CantDealWithHostileFaction = 358, // cant_deal_with_hostile_faction + CannotPlaceMoreCoffer = 359, // cannot_place_more_coffer + CannotDuringSiegePeriod = 360, // cannot_during_siege_period + StoreBackpackNogoods = 361, // store_backpack_nogoods + FamilyInviteOffline = 362, // family_invite_offline + FamilyNoInvitor = 363, // family_no_invitor + FamilySelf = 364, // family_self + FamilyTitle = 365, // family_title + FamilyTitleBad = 366, // family_title_bad + FamilyNoTarget = 367, // family_no_target + FamilyOtherFamily = 368, // family_other_family + FamilyHasFamily = 369, // family_has_family + FamilyNotOwner = 370, // family_not_owner + FamilyAlready = 371, // family_already + FamilyMaximum = 372, // family_maximum + FamilyReject = 373, // family_reject + FamilyCreate = 374, // family_create + FamilyRemoved = 375, // family_removed + FamilyNotExist = 376, // family_not_exist + CannotDemolishHouseWithTooManyCoffers = 377, // cannot_demolish_house_with_too_many_coffers + FamilyKickSelf = 378, // family_kick_self + Family = 379, // family + HouseInvalidHeight = 380, // house_invalid_height + SlaveCannotRepairAlreadySpawned = 381, // slave_cannot_repair_already_spawned + SlaveRepaired = 382, // slave_repaired + HouseUnderWaterOnly = 383, // house_under_water_only + HouseLandOnly = 384, // house_land_only + FamilyOwnerTitle = 385, // family_owner_title + SiegeDeclareBadPeriod = 386, // siege_declare_bad_period + AucInvalidTargetAuctioneer = 387, // auc_invalid_target_auctioneer + AucAuctioneerTooFarAway = 388, // auc_auctioneer_too_far_away + AucNotAuctioneer = 389, // auc_not_auctioneer + AucInvalidItemOrNotInYourBag = 390, // auc_invalid_item_or_not_in_your_bag + AucRefreshDisplay = 391, // auc_refresh_display + AucPermissionDeny = 392, // auc_permission_deny + AucSoulBoundItem = 393, // auc_soul_bound_item + AucNotRepairableItem = 394, // auc_not_repairable_item + AucLowDurabilityItem = 395, // auc_low_durability_item + AucLowDeposit = 396, // auc_low_deposit + AucLowStartMoney = 397, // auc_low_start_money + AucWrongDirectMoney = 398, // auc_wrong_direct_money + AucInvalidSearchKeyword = 399, // auc_invalid_search_keyword + AucBidMoneyUnderTopMost = 400, // auc_bid_money_under_top_most + AucBidMoneyUnderStartMoney = 401, // auc_bid_money_under_start_money + AucBidMoneyOverDirectMoney = 402, // auc_bid_money_over_direct_money + AucDbArticleUpdate = 403, // auc_db_article_update + AucDbCharCacheUpdate = 404, // auc_db_char_cache_update + AucDbItemUpdate = 405, // auc_db_item_update + AucDbBidUpdate = 406, // auc_db_bid_update + DeleteCurrentReturnDistrict = 411, // delete_current_return_district + ChatNotInFamily = 412, // chat_not_in_family + CraftLowExpert = 413, // craft_low_expert + SlaveCannotRemoveWhileInCarryingBackpackDoodadItems = 417, // slave_cannot_remove_while_in_carrying_backpack_doodad_items + MailFailLifespanItem = 418, // mail_fail_lifespan_item + AucLifespanItem = 419, // auc_lifespan_item + TradeItemAboutToExpire = 420, // trade_item_about_to_expire + ConsumeChangeNotSupport = 421, // consume_change_not_support + AucNotSellable = 427, // auc_not_sellable + AucBidSelf = 428, // auc_bid_self + CannotUseSiegeItem = 431, // cannot_use_siege_item + TargetIsNotPlayer = 435, // target_is_not_player + NotEnoughSpace = 436, // not_enough_space + ChatCannotWhisperToHostile = 437, // chat_cannot_whisper_to_hostile + CannotUseInEquippedItem = 438, // cannot_use_in_equipped_item + NoReturnPoint = 439, // no_return_point + ItemCannotUseHere = 440, // item_cannot_use_here + TooManyOwnedDominions = 441, // too_many_owned_dominions + SiegeDeclaredAlready = 442, // siege_declared_already + SiegeDeclaredAlreadyByOther = 443, // siege_declared_already_by_other + SiegeDeclarePirate = 444, // siege_declare_pirate + SiegeParticipantFull = 445, // siege_participant_full + SiegeNotParticipant = 446, // siege_not_participant + OpenPortalAtSiegeArea = 447, // open_portal_at_siege_area + SkillCannotUseInBattleField = 448, // skill_cannot_use_in_battle_field + SkillCannotUseHere = 449, // skill_cannot_use_here + AucInternalError = 450, // auc_internal_error + AucServiceUnavailable = 451, // auc_service_unavailable + AucServerBusy = 452, // auc_server_busy + InstanceVisitLimit = 453, // instance_visit_limit + AucMinimumStartPrice = 454, // auc_minimum_start_price + AucInvalidEntry = 455, // auc_invalid_entry + SiegeBanPirate = 456, // siege_ban_pirate + SiegeBlockDefenseReinforce = 457, // siege_block_defense_reinforce + SiegeWarPeriodOnly = 458, // siege_war_period_only + SiegeMasterOnly = 459, // siege_master_only + SiegeNoTicket = 460, // siege_no_ticket + SiegePeriodMercenaryInSiegeAreaOnly = 461, // siege_period_mercenary_in_siege_area_only + SiegeTicketPriceChanged = 462, // siege_ticket_price_changed + SiegeOnlyDefenseOrOffenseTicketAtOnce = 463, // siege_only_defense_or_offense_ticket_at_once + SiegeOtherOnlyDefenseOrOffenseTicketAtOnce = 464, // siege_other_only_defense_or_offense_ticket_at_once + SiegePeriodWarmupOnly = 465, // siege_period_warmup_only + CannotUseInBattleField = 466, // cannot_use_in_battle_field + ChatNotJoinedChannel = 467, // chat_not_joined_channel + LevelLowToEquip = 468, // level_low_to_equip + ExpeditionDismissInSiege = 469, // expedition_dismiss_in_siege + InstanceLevel = 470, // instance_level + InstanceQuota = 471, // instance_quota + InstanceLeaveParty = 472, // instance_leave_party + InvalidTaxation = 473, // invalid_taxation + PrisonerCannotJoinBattleField = 474, // prisoner_cannot_join_battle_field + Trials = 477, // trials + TrialsAlreadyClosed = 478, // trials_already_closed + TrialsJuryFull = 479, // trials_jury_full + TrialsClosedByDefendant = 480, // trials_closed_by_defendant + MailNotEnoughMoneyToPayTaxes = 481, // mail_not_enough_money_to_pay_taxes + CartEmpty = 482, // cart_empty + NotEnoughCoin = 483, // not_enough_coin + TeleportToSiegeHq = 484, // teleport_to_siege_hq + TeleportToResurrectPos = 485, // teleport_to_resurrect_pos + TrialsDefendantDisconnected = 486, // trials_defendant_disconnected + TrialsClosedByDefendantDisconnect = 487, // trials_closed_by_defendant_disconnect + TaxrateChangeLater = 488, // taxrate_change_later + NotEnoughCommonfarmCapacity = 489, // not_enough_commonfarm_capacity + CannotMoveSoulboundItemToCoffer = 490, // cannot_move_soulbound_item_to_coffer + DismissIndunSuccessed = 491, // dismiss_indun_successed + SlaveUccImprinted = 492, // slave_ucc_imprinted + CommonFarmCountOver = 493, // common_farm_count_over + CommonFarmNotAllowedType = 494, // common_farm_not_allowed_type + CannotFollowInCombat = 495, // cannot_follow_in_combat + ChatNotRaidOwner = 496, // chat_not_raid_owner + CannotFollowNonParty = 497, // cannot_follow_non_party + CannotFollowTooFar = 498, // cannot_follow_too_far + MsgFollowingBegin = 499, // msg_following_begin + MsgFollowingEnd = 500, // msg_following_end + CannotAddFriendSelf = 501, // cannot_add_friend_self + AddFriend = 502, // add_friend + DeleteFriend = 503, // delete_friend + BadDuelTarget = 504, // bad_duel_target + AlreadyInDuel = 505, // already_in_duel + OtherAlreadyInDuel = 506, // other_already_in_duel + TargetRejectedDuel = 507, // target_rejected_duel + ActabilityNotEnoughPoint = 508, // actability_not_enough_point + ActabilityCanUpgradeAnyMore = 509, // actability_can_upgrade_any_more + ActabilityCanUpgradeSelectionCountLimit = 510, // actability_can_upgrade_selection_count_limit + ActabilityCanDowngradeAnyMore = 511, // actability_can_downgrade_any_more + StoreCantSellSameZone = 512, // store_cant_sell_same_zone + BadDuelSelf = 513, // bad_duel_self + NotEnoughBankMoney = 514, // not_enough_bank_money + DuelOtherBusy = 515, // duel_other_busy + DuelBadLocation = 516, // duel_bad_location + TargetTooFar = 517, // target_too_far + LevelLowToUse = 518, // level_low_to_use + AucKeywordOrCategoryNeeded = 519, // auc_keyword_or_category_needed + AucInvalidLevelRange = 520, // auc_invalid_level_range + AucBidNothingItem = 521, // auc_bid_nothing_item + FactionRelationSubjectNotFound = 522, // faction_relation_subject_not_found + FactionRelationAlreadyHostile = 523, // faction_relation_already_hostile + FactionRelationAlreadyFriendly = 524, // faction_relation_already_friendly + FactionRelationProposalNotFound = 525, // faction_relation_proposal_not_found + FactionRelationProposalAlreadyExists = 526, // faction_relation_proposal_already_exists + FactionRelationCannotChangeYet = 527, // faction_relation_cannot_change_yet + FactionRelationCannotChangeWithSelf = 528, // faction_relation_cannot_change_with_self + FamilyAlreadyOwner = 529, // family_already_owner + LevelHighToUse = 530, // level_high_to_use + LevelHighToEquip = 531, // level_high_to_equip + QuestRewardedByMail = 532, // quest_rewarded_by_mail + CastleCannotLocateInvalidArea = 533, // castle_cannot_locate_invalid_area + DiceRollInProgress = 534, // dice_roll_in_progress + BlockedForFreeTrial = 535, // blocked_for_free_trial + CannotTradeWithFreeTrial = 536, // cannot_trade_with_free_trial + CannotMoveLifespanItemIntoCoffer = 537, // cannot_move_lifespan_item_into_coffer + TradeTargetIsNotPossibleState = 538, // trade_target_is_not_possible_state + CantTradeWithOtherView = 539, // cant_trade_with_other_view + SlaveSpawnErrorNeedRepairTime = 540, // slave_spawn_error_need_repair_time + AucMaxBids = 541, // auc_max_bids + AucMaxPosts = 542, // auc_max_posts + CannotChangeBackpackInGliding = 543, // cannot_change_backpack_in_gliding + CannotJoinTrialFromInstantZone = 544, // cannot_join_trial_from_instant_zone + WhisperDisabled = 545, // whisper_disabled + AucCannotCancelIfBid = 546, // auc_cannot_cancel_if_bid + QuestMailSent = 547, // quest_mail_sent + ExceedMaxDominionGateOrWall = 548, // exceed_max_dominion_gate_or_wall + TrialsCannotJoinAfterStart = 549, // trials_cannot_join_after_start + Community = 550, // community + UserNotExist = 551, // user_not_exist + UpdateUccSlaveExist = 552, // update_ucc_slave_exist + CannotAddExistingMember = 553, // cannot_add_existing_member + CannotExitWhileInTrial = 554, // cannot_exit_while_in_trial + MailFailDisableArchebill = 555, // mail_fail_disable_archebill + CannotFindInFriendList = 556, // cannot_find_in_friend_list + CannotAcceptJuryInvitationWithBackpack = 557, // cannot_accept_jury_invitation_with_backpack + CannotDuelDuringForceAttack = 558, // cannot_duel_during_force_attack + CannotDuelDuringForceAttackOther = 559, // cannot_duel_during_force_attack_other + CannotForceAttackDuringDuel = 560, // cannot_force_attack_during_duel + InviteError = 561, // invite_error + InviteConsideringOtherInvitation = 562, // invite_considering_other_invitation + InviteBadStatus = 563, // invite_bad_status + InviteNoGmTarget = 564, // invite_no_gm_target + CannotLocateDoodadNow = 565, // cannot_locate_doodad_now + ExpeditionCannotJoinMemberFull = 566, // expedition_cannot_join_member_full + HouseCannotDemolishUnpaidTax = 567, // house_cannot_demolish_unpaid_tax + ExpeditionOwnerCannotChangeDuringSiege = 568, // expedition_owner_cannot_change_during_siege + CannotFindInView = 569, // cannot_find_in_view + BotReportAlreadyReportedByYou = 570, // bot_report_already_reported_by_you + BotReportAlreadyReportedByOther = 571, // bot_report_already_reported_by_other + CannotReportBot = 572, // cannot_report_bot + BotReportExceededDailyLimit = 573, // bot_report_exceeded_daily_limit + CannotChangeEquipWhenDead = 574, // cannot_change_equip_when_dead + CannotDeleteCharWhileOnPlay = 575, // cannot_delete_char_while_on_play + NoPortalBook = 576, // no_portal_book + NotEnoughBloodyArchium = 577, // not_enough_bloody_archium + CannotRequestCommonfarmInfoInInstantZone = 578, // cannot_request_commonfarm_info_in_instant_zone + CannotDeleteCharWhilePenalty = 579, // cannot_delete_char_while_penalty + HouseCannotLoacateInvalidCategoryArea = 580, // house_cannot_loacate_invalid_category_area + SiegeNoRightsInExpedition = 581, // siege_no_rights_in_expedition + DominionNotDeclareTime = 582, // dominion_not_declare_time + SlaveSpawnErrorInvalidArea = 583, // slave_spawn_error_invalid_area + CannotSetBountyForNotWanted = 584, // cannot_set_bounty_for_not_wanted + CannotSetBountyForSuchName = 585, // cannot_set_bounty_for_such_name + CannotSetBounty = 586, // cannot_set_bounty + AuctionUccPost = 587, // auction_ucc_post + InvitationCanceledTimeout = 588, // invitation_canceled_timeout + IngameShopBuySuccess = 589, // ingame_shop_buy_success + IngameShopBuyFail = 590, // ingame_shop_buy_fail + IngameShopNotEnoughAaCash = 591, // ingame_shop_not_enough_aa_cash + IngameShopNotEnoughAaPoint = 592, // ingame_shop_not_enough_aa_point + IngameShopBuyGiftSuccess = 593, // ingame_shop_buy_gift_success + IngameShopBuyGiftFail = 594, // ingame_shop_buy_gift_fail + IngameShopSoldOut = 595, // ingame_shop_sold_out + IngameShopExpiredSellByDate = 596, // ingame_shop_expired_sell_by_date + UccLoading = 597, // ucc_loading + UccLoadingEmblem = 598, // ucc_loading_emblem + UccInvalidData = 599, // ucc_invalid_data + UccInvalidEmblem = 600, // ucc_invalid_emblem + UccInternalFileLoad = 601, // ucc_internal_file_load + UccInternalTextureLoad = 602, // ucc_internal_texture_load + IngameShopBuyLowLevel = 603, // ingame_shop_buy_low_level + IngameShopBuyQuestIncomplete = 604, // ingame_shop_buy_quest_incomplete + SpecialtyNotBuyNow = 605, // specialty_not_buy_now + QuestMailNotEnoughItems = 606, // quest_mail_not_enough_items + HouseCannotCreateConstructTaxAbnormal = 607, // house_cannot_create_construct_tax_abnormal + InvalidPortal = 608, // invalid_portal + NotMyPortal = 609, // not_my_portal + CannotUsePortalWithBackpack = 610, // cannot_use_portal_with_backpack + CannotUsePortalInTrial = 611, // cannot_use_portal_in_trial + SoldBackpackRefundSentByMail = 612, // sold_backpack_refund_sent_by_mail + PermissionChanged = 613, // permission_changed + InvalidHouseInfo = 614, // invalid_house_info + HouseCannotOwnMoreHouselessCondition = 615, // house_cannot_own_more_houseless_condition + HouseCannotOwnMoreExistingCategoryCondition = 616, // house_cannot_own_more_existing_category_condition + NotEnoughLivingPoint = 617, // not_enough_living_point + MailDelayDemolishedHouseByUnpaidTax = 618, // mail_delay_demolished_house_by_unpaid_tax + SlaveSpawnErrorOffedZone = 619, // slave_spawn_error_offed_zone + SlaveRemovedOffedZone = 620, // slave_removed_offed_zone + QuestDailyLimit = 621, // quest_daily_limit + MailDelayDestroyedShipyard = 622, // mail_delay_destroyed_shipyard + IngameShopFindCharacterNameFail = 623, // ingame_shop_find_character_name_fail + CannotDeleteCharWhileBotSuspected = 624, // cannot_delete_char_while_bot_suspected + SiegeCannotDeclareNearResurrectPos = 625, // siege_cannot_declare_near_resurrect_pos + SpecialtyMargin = 626, // specialty_margin + StoreCantBuyWithLivingPoint = 627, // store_cant_buy_with_living_point + HousingActabilityDecoLimited = 628, // housing_actability_deco_limited + AcatbilityDecoArrangFail = 629, // acatbility_deco_arrang_fail + ArrestFailedDueToFullCourt = 630, // arrest_failed_due_to_full_court + SpawnedSlaveExists = 631, // spawned_slave_exists + EnterInstReqItem = 632, // enter_inst_req_item + SiegeCannotDeclareNearHouse = 633, // siege_cannot_declare_near_house + BlockedForPromotionUser = 634, // blocked_for_promotion_user + ChTransferCannotBecomeExpeditionOwner = 635, // ch_transfer_cannot_become_expedition_owner + ChTransferCannotBuild = 636, // ch_transfer_cannot_build + ChTransferCannotDeleteCharacter = 637, // ch_transfer_cannot_delete_character + ChTransferCannotPostOrBidAuction = 638, // ch_transfer_cannot_post_or_bid_auction + SiegeAlreadyParticipating = 639, // siege_already_participating + SlaveEscapeTooFarFromSlave = 640, // slave_escape_too_far_from_slave + MustEquipInstrumentItem = 641, // must_equip_instrument_item + HouseCannotSellAsNotOwner = 642, // house_cannot_sell_as_not_owner + HouseCannotSellAsCastle = 643, // house_cannot_sell_as_castle + HouseCannotSellAsType = 644, // house_cannot_sell_as_type + HouseCannotSellAsDelayedTax = 645, // house_cannot_sell_as_delayed_tax + HouseCannotSellAsAlreadyForSale = 646, // house_cannot_sell_as_already_for_sale + HouseCannotSellAsNotEnoughSeal = 647, // house_cannot_sell_as_not_enough_seal + HouseCannotSellAsDesignatedBuyerNotFound = 648, // house_cannot_sell_as_designated_buyer_not_found + HouseCannotSellAsDbError = 649, // house_cannot_sell_as_db_error + HouseCannotCancelSellAsNotOwner = 651, // house_cannot_cancel_sell_as_not_owner + HouseCannotCancelSellAsNotForSale = 652, // house_cannot_cancel_sell_as_not_for_sale + HouseCannotCancelSellAsDbError = 653, // house_cannot_cancel_sell_as_db_error + HouseCannotBuyAsNotForSale = 654, // house_cannot_buy_as_not_for_sale + HouseCannotBuyAsOwner = 655, // house_cannot_buy_as_owner + HouseCannotBuyAsNotDesignatedBuyer = 656, // house_cannot_buy_as_not_designated_buyer + HouseCannotBuyAsNotEnoughMoney = 657, // house_cannot_buy_as_not_enough_money + HouseCannotBuyAsSaleInfoChanged = 658, // house_cannot_buy_as_sale_info_changed + HouseCannotBuyAsDbError = 659, // house_cannot_buy_as_db_error + CannotDecorateHouseDuringWar = 660, // cannot_decorate_house_during_war + SiegeCannotDeclareNearOtherZone = 661, // siege_cannot_declare_near_other_zone + DominionClosed = 662, // dominion_closed + AddCharacterSlotFail = 663, // add_character_slot_fail + ItemSecureCondition = 664, // item_secure_condition + GradeEnchantMax = 665, // grade_enchant_max + HouseCannotSellAsUnderConstruction = 668, // house_cannot_sell_as_under_construction + CannotRechargeWhenEquipped = 669, // cannot_recharge_when_equipped + NoUsableExp = 670, // no_usable_exp + NeedParty = 671, // need_party + CannotForceAttackDuringBattleField = 672, // cannot_force_attack_during_battle_field + NoMatchGenderToEquip = 673, // no_match_gender_to_equip + UserMusicCannotPlayDueToDifficulty = 674, // user_music_cannot_play_due_to_difficulty + RunawayCantApplyBattleField = 675, // runaway_cant_apply_battle_field + MailPayChargeFirst = 676, // mail_pay_charge_first + SpecialtyCoinMargin = 677, // specialty_coin_margin + InstantGameCannotJoinByBuff = 678, // instant_game_cannot_join_by_buff + InstantGameInvalidData = 679, // instant_game_invalid_data + InstantGameCannotJoinByNoSeamless = 680, // instant_game_cannot_join_by_no_seamless + HouseCannotSellToOneself = 681, // house_cannot_sell_to_oneself + UserNoteCannotSave = 682, // user_note_cannot_save + IngameShopBuyNoDuplicateItem = 683, // ingame_shop_buy_no_duplicate_item + DominionNationalTaxInvalidRate = 684, // dominion_national_tax_invalid_rate + DominionNationalTaxNoPermission = 685, // dominion_national_tax_no_permission + NotEnoughExpandItem = 686, // not_enough_expand_item + NotEnoughExpandItemAndMoney = 687, // not_enough_expand_item_and_money + SecondPassSettedMsg = 688, // second_pass_setted_msg + NotEnoughBmMileage = 689, // not_enough_bm_mileage + ModifyBmMileage = 690, // modify_bm_mileage + ScheduleItemSent = 691, // schedule_item_sent + CannotDyeingWhenEquipped = 692, // cannot_dyeing_when_equipped + FactionCannotImmigrateAsGeneral = 693, // faction_cannot_immigrate_as_general + FactionCannotImmigrateAsPirate = 694, // faction_cannot_immigrate_as_pirate + FactionCannotInviteImmigrationAsNoPermission = 697, // faction_cannot_invite_immigration_as_no_permission + AllEquipmentsAreSecured = 698, // all_equipments_are_secured + AllEquipmentsAreUnsecured = 699, // all_equipments_are_unsecured + ItemNotForUnderwaterCreature = 700, // item_not_for_underwater_creature + ItemOnlyForUnderwaterCreature = 701, // item_only_for_underwater_creature + ConnotUseWhileHaveMusicalBuffs = 702, // connot_use_while_have_musical_buffs + ExpeditionOwnerCannotEngraveGuardTower = 703, // expedition_owner_cannot_engrave_guard_tower + FactionKickTargetNotFound = 704, // faction_kick_target_not_found + FactionKickOtherFaction = 705, // faction_kick_other_faction + DemolishedHouseByExpiration = 706, // demolished_house_by_expiration + NotEnoughAaPoint = 707, // not_enough_aa_point + NotEnoughBankAaPoint = 708, // not_enough_bank_aa_point + StoreCantBuyWithAaPoint = 709, // store_cant_buy_with_aa_point + StoreCantBuyWithMoneyWithAaPoint = 710, // store_cant_buy_with_money_with_aa_point + FactionOwnerCannotDelete = 711, // faction_owner_cannot_delete + ChTransferHasMould = 712, // ch_transfer_has_mould + CraftNotHasMould = 713, // craft_not_has_mould + CraftAlreadyMould = 714, // craft_already_mould + CraftMouldNotFound = 715, // craft_mould_not_found + CraftMouldNotReady = 716, // craft_mould_not_ready + InstantGameCannotLeave = 717, // instant_game_cannot_leave + FactionDiplomacyInvalidSubject = 718, // faction_diplomacy_invalid_subject + TransferChCannotEngrave = 720, // transfer_ch_cannot_engrave + InviteEnterBeautyshop = 721, // invite_enter_beautyshop + NotEnoughRequiredItem = 722, // not_enough_required_item + CannotEditGenderAndModelAsDbError = 723, // cannot_edit_gender_and_model_as_db_error + DominionNationalTaxLater = 725, // dominion_national_tax_later + FactionKickExpeditionMember = 726, // faction_kick_expedition_member + MailReceiverToBeTransferred = 727, // mail_receiver_to_be_transferred + FactionCannotImmigrateAsLevelLow = 728, // faction_cannot_immigrate_as_level_low + InstantGameCancelForOtherInstant = 729, // instant_game_cancel_for_other_instant + FactionCannotImmigrateToUserAsAlreadyMember = 730, // faction_cannot_immigrate_to_user_as_already_member + FactionCannotImmigrateToUserAsFactionOwner = 731, // faction_cannot_immigrate_to_user_as_faction_owner + FactionCannotImmigrateToUserAsExpeditionMember = 732, // faction_cannot_immigrate_to_user_as_expedition_member + FactionCannotImmigrateToOrigAsAlreadyMember = 733, // faction_cannot_immigrate_to_orig_as_already_member + FactionCannotImmigrateToOrigAsFactionOwner = 734, // faction_cannot_immigrate_to_orig_as_faction_owner + FactionCannotImmigrateToOrigAsExpeditionMember = 735, // faction_cannot_immigrate_to_orig_as_expedition_member + FactionCannotImmigrationAsOneself = 736, // faction_cannot_immigration_as_oneself + ItemLookConvertAsInvalidCombination = 737, // item_look_convert_as_invalid_combination + ItemLookConvertAsNotUseAsStat = 738, // item_look_convert_as_not_use_as_stat + ItemLookConvertAsNotUseAsSkin = 739, // item_look_convert_as_not_use_as_skin + Maintenance = 740, // maintenance + SiegeCannotDeclareObstacle = 741, // siege_cannot_declare_obstacle + ItemSocketsFull = 742, // item_sockets_full + ItemSocketsEmpty = 743, // item_sockets_empty + GenderTransferAsGenderEquipment = 744, // gender_transfer_as_gender_equipment + SecondPassCheckOverFailed = 745, // second_pass_check_over_failed + RankInvalidData = 746, // rank_invalid_data + RankCannotRequestDataTime = 747, // rank_cannot_request_data_time + OnlyNationOwner = 748, // only_nation_owner + LocateInvalidDominionArea = 749, // locate_invalid_dominion_area + NoMoreNationalMonument = 750, // no_more_national_monument + CantPutUpNationalMonumentDuringSiegePeriod = 751, // cant_put_up_national_monument_during_siege_period + StoreOneTimeSale = 752, // store_one_time_sale + ItemLookConvertAsDiffGender = 753, // item_look_convert_as_diff_gender + ItemPackCondition = 754, // item_pack_condition + UnlawfulCannotEngrave = 755, // unlawful_cannot_engrave + CannotHangDuringTeleport = 756, // cannot_hang_during_teleport + NationOwnerAtPosOnly = 757, // nation_owner_at_pos_only + DominionOwnerAtPosOnly = 758, // dominion_owner_at_pos_only + AlreadyInNonPvpDuration = 759, // already_in_non_pvp_duration + SiegeNearWarPeriod = 760, // siege_near_war_period + ExpeditionAlreadyMember = 761, // expedition_already_member + ExpeditionNotBeginner = 762, // expedition_not_beginner + ExpeditionBeginnerNotFound = 763, // expedition_beginner_not_found + ExpeditionBeginnerFull = 764, // expedition_beginner_full + ExpeditionBeginnerCannotJoinAsInvalidFaction = 765, // expedition_beginner_cannot_join_as_invalid_faction + HouseCannotConstructInAreaByMaxConstructCount = 766, // house_cannot_construct_in_area_by_max_construct_count + SlaveEquipmentNoBuff = 767, // slave_equipment_no_buff + SlaveEquipmentNotOwner = 768, // slave_equipment_not_owner + RankRewardSent = 769, // rank_reward_sent + FactionCannotImmigrateAsCombat = 770, // faction_cannot_immigrate_as_combat + AucPostBlocked = 771, // auc_post_blocked + PremiumServiceBuySuccess = 772, // premium_service_buy_success + PremiumServiceBuyFail = 773, // premium_service_buy_fail + PremiumServiceNotEnoughAaCash = 774, // premium_service_not_enough_aa_cash + PremiumServiceNotEnoughAaPoint = 775, // premium_service_not_enough_aa_point + CanNotOnMovingPhysicalVehicle = 776, // can_not_on_moving_physical_vehicle + RankInvalidBigFishData = 777, // rank_invalid_big_fish_data + IngameShopBuyFailAaPoint = 778, // ingame_shop_buy_fail_aa_point + IngameShopFindCharacterSameAccount = 779, // ingame_shop_find_character_same_account + IngameShopLimitedBuyForTotalPrice = 780, // ingame_shop_limited_buy_for_total_price + SocketTargetLevel = 781, // socket_target_level + IngameShopNeedCheckSecondPassword = 782, // ingame_shop_need_check_second_password + FactionInviteBattlefield = 783, // faction_invite_battlefield + IngameShopNotEnoughBmMileage = 784, // ingame_shop_not_enough_bm_mileage + MailCannotSendSinceLevelLow = 785, // mail_cannot_send_since_level_low + ChatCannotSendSinceLevelLow = 786, // chat_cannot_send_since_level_low + BuffHigher = 787, // buff_higher + AlreadyGenderTransfered = 788, // already_gender_transfered + IngameShopBuyFailInvalidAccount = 789, // ingame_shop_buy_fail_invalid_account + IngameShopChracterDeleteRequested = 790, // ingame_shop_chracter_delete_requested + IngameShopChracterTransferRequested = 791, // ingame_shop_chracter_transfer_requested + RankNoOngoingRanks = 792, // rank_no_ongoing_ranks + CannotReusePortalInDelayTime = 793, // cannot_reuse_portal_in_delay_time + NotPlaySensitiveOperation = 794, // not_play_sensitive_operation + AchievementItemSent = 795, // achievement_item_sent + CannotRecoverAllNotEnough = 796, // cannot_recover_all_not_enough + CannotRecoverAllLevelUp = 797, // cannot_recover_all_level_up + MailCoolTime = 798, // mail_cool_time + MailRepetition = 799, // mail_repetition + SlaveEquipmentLoadedItem = 800, // slave_equipment_loaded_item + ChTransferCannotImmigrate = 801, // ch_transfer_cannot_immigrate + CannotAutoRegisterSkill = 802, // cannot_auto_register_skill + SlaveEquipErrorRequireSlotAndItem = 803, // slave_equip_error_require_slot_and_item + SlaveUnequipErrorUnequipFirst = 804, // slave_unequip_error_unequip_first + AucInvalidPostAuthority = 805, // auc_invalid_post_authority + CanNotUseSystemHotKey = 806, // can_not_use_system_hot_key + OnlyExpeditionOwner = 807, // only_expedition_owner + OnlyExpeditionMember = 808, // only_expedition_member + RevertInvalidItemLook = 809, // revert_invalid_item_look + TradeLockDelay = 810, // trade_lock_delay + HouseCannotPrepayForSale = 811, // house_cannot_prepay_for_sale + HouseCannotPrepayUnpaidTax = 812, // house_cannot_prepay_unpaid_tax + HouseCannotPrepayUnderConstruction = 813, // house_cannot_prepay_under_construction + HouseCannotPrepayAnyMore = 814, // house_cannot_prepay_any_more + HouseCannotSellAsPrepaidTax = 815, // house_cannot_sell_as_prepaid_tax + QuestToday = 816, // quest_today + SlaveEquipmentNotToggled = 817, // slave_equipment_not_toggled + FactionInviteRestrictionTime = 818, // faction_invite_restriction_time + QuestItemCannotInsertIntoCoffer = 819, // quest_item_cannot_insert_into_coffer + NotAcceptableItemCategoryTypeForPrivateCoffer = 820, // not_acceptable_item_category_type_for_private_coffer + CannotRideBackpacker = 821, // cannot_ride_backpacker + SlaveOverSpeed = 822, // slave_over_speed + NotSupportedGraphicCard = 823, // not_supported_graphic_card + NotSupportedGraphicCardD3dtexturecapsPow2 = 824, // not_supported_graphic_card_d3dtexturecaps_pow2 + NotEnoughGraphicMemory = 825, // not_enough_graphic_memory + NotEnoughShaderVersion = 826, // not_enough_shader_version + NotEnoughDesktopResolution = 827, // not_enough_desktop_resolution + InvalidRepairAuthorityInBag = 828, // invalid_repair_authority_in_bag + SlaveAndMateCannotIntoBankOrCoffer = 829, // slave_and_mate_cannot_into_bank_or_coffer + ChTransferCannotBuyHouse = 830, // ch_transfer_cannot_buy_house + AucPostAlreadyAuthority = 831, // auc_post_already_authority + AucPostNonAuthority = 832, // auc_post_non_authority + MailFailLevelLimited = 833, // mail_fail_level_limited + ImpossibleDeadState = 834, // impossible_dead_state + ImpossibleCombatState = 835, // impossible_combat_state + InstanceInvalidEnter = 836, // instance_invalid_enter + InstanceEnterCount = 837, // instance_enter_count + InstanceTicket = 838, // instance_ticket + MailFailRestrictOwnerChange = 839, // mail_fail_restrict_owner_change + FailedEnterInstanceBecauseSlave = 840, // failed_enter_instance_because_slave + ChatNotInTrial = 841, // chat_not_in_trial + OverAaPointMaxLimit = 842, // over_aa_point_max_limit + WorldRestrictOwnerChange = 843, // world_restrict_owner_change + InstantGameCannotJoinByBotChecking = 844, // instant_game_cannot_join_by_bot_checking + InstantGameCannotJoinByTrade = 845, // instant_game_cannot_join_by_trade + NotTeleportCombat = 846, // not_teleport_combat + NotTeleportDead = 847, // not_teleport_dead + NotEnoughEmptySlotsInBag = 848, // not_enough_empty_slots_in_bag + NoPermissionOpenPortal = 849, // no_permission_open_portal + IssuanceOfMobilizationOrderHeroOnly = 850, // issuance_of_mobilization_order_hero_only + IssuanceOfMobilizationOrderNotMyDominion = 851, // issuance_of_mobilization_order_not_my_dominion + NotExistReturnPoint = 852, // not_exist_return_point + WrongLeadershipPoint = 853, // wrong_leadership_point + WrongHero = 854, // wrong_hero + TimeoutAndCancel = 855, // timeout_and_cancel + OngoingHandOverOwner = 856, // ongoing_hand_over_owner + NotHeroAbstainPeriod = 857, // not_hero_abstain_period + NotHeroVotingPeriod = 858, // not_hero_voting_period + NotHeroAbstainVotingPeriod = 859, // not_hero_abstain_voting_period + NotHeroCandidate = 860, // not_hero_candidate + NotHeroVoterCondition = 861, // not_hero_voter_condition + EmptyHeroCandidates = 862, // empty_hero_candidates + UnfinishedBuildHouse = 863, // unfinished_build_house + IssuanceOfMobilizationOrderNoNation = 864, // issuance_of_mobilization_order_no_nation + HousingAreaNotActivated = 865, // housing_area_not_activated + PingLineOverCount = 866, // ping_line_over_count + DeleteRepresentCharacter = 867, // delete_represent_character + TodayAssignmentItemSent = 868, // today_assignment_item_sent + AllOfEntryRondomUnitAttributesAlreadyExists = 869, // all_of_entry_rondom_unit_attributes_already_exists + EntryRandomUnitAttributesDoNotExist = 870, // entry_random_unit_attributes_do_not_exist + FailedToAddRandomUnitAttributes = 871, // failed_to_add_random_unit_attributes + StoreCantBuyWithContributionPoint = 872, // store_cant_buy_with_contribution_point + NotEnoughContributionPoint = 873, // not_enough_contribution_point + NotEnoughExpeditionLevel = 874, // not_enough_expedition_level + AucInvalidHudAuthority = 875, // auc_invalid_hud_authority + AccountAttendanceAlreadyChecked = 876, // account_attendance_already_checked + BagFullAndSentByMail = 877, // bag_full_and_sent_by_mail + ExpeditionNotFound = 878, // expedition_not_found + ExpeditionInvalidExp = 879, // expedition_invalid_exp + ExpeditionCannotLevelUp = 880, // expedition_cannot_level_up + ExpeditionProgressLevelUp = 881, // expedition_progress_level_up + TargetExpeditionIsUnderProtection = 882, // target_expedition_is_under_protection + TargetExpeditionIsLowLevel = 883, // target_expedition_is_low_level + TargetExpeditionGearScore = 884, // target_expedition_gear_score + TargetExpeditionIsInWar = 885, // target_expedition_is_in_war + ExpeditionIsInUnderProtection = 886, // expedition_is_in_under_protection + ExpeditionIsLowLevel = 887, // expedition_is_low_level + ExpeditionCannotJoinDuringWar = 888, // expedition_cannot_join_during_war + IssuanceOfMobilizationOrderCountMax = 889, // issuance_of_mobilization_order_count_max + OnlyDominionExpeditionMember = 890, // only_dominion_expedition_member + MailFailReportedSpamMail = 891, // mail_fail_reported_spam_mail + SummonFail = 892, // summon_fail + SummonNotEnoughSpace = 893, // summon_not_enough_space + SummonCancelNotMove = 894, // summon_cancel_not_move + ImpossibleMove = 895, // impossible_move + ExpeditionOwnerChangeTooOften = 896, // expedition_owner_change_too_often + TeamInviteeInBattleField = 897, // team_invitee_in_battle_field + TeamInvitorInBattleField = 898, // team_invitor_in_battle_field + ExpeditionCreateApplicant = 899, // expedition_create_applicant + DeleteCharacterFailScheduleItemSelCharLock = 900, // delete_character_fail_schedule_item_sel_char_lock + ExpeditionSummonNotInstant = 901, // expedition_summon_not_instant + ExpeditionApplicantLimitCount = 902, // expedition_applicant_limit_count + ExpeditionSummonNotLeave = 903, // expedition_summon_not_leave + InvalidHudBattlefieldAuthority = 904, // invalid_hud_battlefield_authority + CanNotUseItemSkillByWorldRestriction = 905, // can_not_use_item_skill_by_world_restriction + ExpeditionBlockedWord = 906, // expedition_blocked_word + OnlyDominionNationMember = 907, // only_dominion_nation_member + ExpeditionMobilizationBuff = 908, // expedition_mobilization_buff + ExpeditionDismissDuringChanneling = 909, // expedition_dismiss_during_channeling + MateSpawnErrorDead = 910, // mate_spawn_error_dead + DisableTwoToneHair = 911, // disable_two_tone_hair + BuffCannotUseInBattleField = 912, // buff_cannot_use_in_battle_field + CanNotLearnSkillInPreviewMode = 913, // can_not_learn_skill_in_preview_mode + HousingAreaNotOpen = 914, // housing_area_not_open + CannotUseSiegeSkill = 915, // cannot_use_siege_skill + AlreadySavedSkillSet = 916, // already_saved_skill_set + CannotMoveItemToCoffer = 917, // cannot_move_item_to_coffer + HousePackageDemolishFailedNotEnoughSeal = 918, // house_package_demolish_failed_not_enough_seal + HousePackageDemolishFailedUnderConstruction = 919, // house_package_demolish_failed_under_construction + CannotDeleteHasComercialMailItem = 920, // cannot_delete_has_comercial_mail_item + IngameShopCannotUseAacoinForGift = 921, // ingame_shop_cannot_use_aacoin_for_gift + CreateExpeditionRejoinError = 922, // create_expedition_rejoin_error + NationMemberLimitJoin = 923, // nation_member_limit_join + NationMemberLimitInvite = 924, // nation_member_limit_invite + ExceedMaxDominionKeep = 925, // exceed_max_dominion_keep + InZoneGroupHousingExist = 926, // in_zone_group_housing_exist + InZoneGroupHousingNotExist = 927, // in_zone_group_housing_not_exist + InstanceMatchingFailed = 928, // instance_matching_failed + ExpeditionLevelNotMatch = 929, // expedition_level_not_match + ExceedMaxDominionBuilding = 930, // exceed_max_dominion_building + HousingNoAssetDiagonal = 931, // housing_no_asset_diagonal + ChangeNationOwnerToHero = 932, // change_nation_owner_to_hero + ChangeNationOwnerToSelf = 933, // change_nation_owner_to_self + ChangeNationOwnerToNotNational = 934, // change_nation_owner_to_not_national + ChangeNationOwnerToChTransfer = 935, // change_nation_owner_to_ch_transfer + ChangeNationOwnerTooOften = 936, // change_nation_owner_too_often + AlreadyRelationHostile = 937, // already_relation_hostile + InstanceGmEventEnded = 938, // instance_gm_event_ended + InstanceGmEventFailure = 939, // instance_gm_event_failure + NotRelationVoteParticipation = 940, // not_relation_vote_participation + CannotRideWithBackpack = 941, // cannot_ride_with_backpack + CanRenameExpeditionOwner = 942, // can_rename_expedition_owner + RenameExpeditionMayBePossibleAfterThirtiethDays = 943, // rename_expedition_may_be_possible_after_thirtieth_days + TargetBagIsFull = 944, // target_bag_is_full + TradeBan = 945, // trade_ban + ItemLookConvertAsNotUseAsExtract = 946, // item_look_convert_as_not_use_as_extract + ReputationBadZone = 947, // reputation_bad_zone + ReputationTargetLevelLow = 948, // reputation_target_level_low + ReputationOwnerLevelLow = 949, // reputation_owner_level_low + ReputationOwnerLeadershipLow = 950, // reputation_owner_leadership_low + ReputationIsMe = 951, // reputation_is_me + ReputationNotSameTeam = 952, // reputation_not_same_team + ReputationNotSameFaction = 953, // reputation_not_same_faction + ReputationNotTime = 954, // reputation_not_time + ImmigrationExpeditonMemberOver = 955, // immigration_expediton_member_over + ImmigrationExpeditonFull = 956, // immigration_expediton_full + ImmigrationExpeditonNotPirate = 957, // immigration_expediton_not_pirate + ImmigrationExpeditonLimitLevel = 958, // immigration_expediton_limit_level + ImmigrationExpeditonNotEnoughOwnerLevel = 959, // immigration_expediton_not_enough_owner_level + ImmigrationExpeditonNotChangeOwner = 960, // immigration_expediton_not_change_owner + CannotRide = 961, // cannot_ride + NonResident = 962, // non_resident + NeedMoreResidentServicePoint = 963, // need_more_resident_service_point + IntensifiedExpertDowngradeNeedItem = 964, // intensified_expert_downgrade_need_item + ChatCannotSendByBuff = 965, // chat_cannot_send_by_buff + CannotTarget = 966, // cannot_target + CannotChangeTarget = 967, // cannot_change_target + RemoveHighAbilityLevelLimit = 968, // remove_high_ability_level_limit + NuonsArrowTargetNotSelected = 969, // nuons_arrow_target_not_selected + NuonsArrowTargetInvalid = 970, // nuons_arrow_target_invalid + NotChangeFamilyRoleTime = 973, // not_change_family_role_time + NotJoinFamily = 974, // not_join_family + BackpackOneByOne = 975, // backpack_one_by_one + FamilyRoleNotMatch = 976, // family_role_not_match + ImmigrationExpeditonNotAccpet = 977, // immigration_expediton_not_accpet + FamilyNameInvalid = 978, // family_name_invalid + FamilyNameBad = 979, // family_name_bad + NationImmigrationApplyCountMax = 980, // nation_immigration_apply_count_max + IngameShopTimeout = 981, // ingame_shop_timeout + FriendNameInvalid = 982, // friend_name_invalid + BlockNameInvalid = 983, // block_name_invalid + ExpeditionNameInvalid = 984, // expedition_name_invalid + NationNameInvalid = 985, // nation_name_invalid + CannotForceAttack = 986, // cannot_force_attack + TradegoodsStockLimitExceed = 987, // tradegoods_stock_limit_exceed + NotEnoughAbilityLevel = 988, // not_enough_ability_level + ConditionNotMatch = 989, // condition_not_match + SpecialtyStockFull = 990, // specialty_stock_full + TradegoodNotPassedTradepost = 991, // tradegood_not_passed_tradepost + TradegoodsStockEmpty = 992, // tradegoods_stock_empty + HeirExpFull = 993, // heir_exp_full + CannotFollow = 994, // cannot_follow + NotEnoughItemType = 995, // not_enough_item_type + UseItemType = 996, // use_item_type + InvalidSlaveFollowCondition = 997, // invalid_slave_follow_condition + AvailableLootItem = 998, // available_loot_item + NotAvailableLootItem = 999, // not_available_loot_item + NotChangeRaidRecruitOwner = 1000, // not_change_raid_recruit_owner + NotChangeRaidRecruitTarget = 1001, // not_change_raid_recruit_target + NotJoinRaid = 1002, // not_join_raid + StoreCantBuyWithItemPoint = 1003, // store_cant_buy_with_item_point + NotEnoughItemPoint = 1004, // not_enough_item_point + IngameShopNotEnoughGold = 1005, // ingame_shop_not_enough_gold + FamilyLevelNotMatch = 1006, // family_level_not_match + SecondPassNotSettedMsg = 1007, // second_pass_not_setted_msg + RaidJointErrorDismissed = 1008, // raid_joint_error_dismissed + TargetNotRaidOwner = 1009, // target_not_raid_owner + TargetAlreadyRaidJointed = 1010, // target_already_raid_jointed + HouseCannotRotate = 1011, // house_cannot_rotate + RaidCantnotApplyMyRaid = 1012, // raid_cantnot_apply_my_raid + RaidApplyIsDuplicate = 1013, // raid_apply_is_duplicate + RaidJointedCannotEnterInstance = 1014, // raid_jointed_cannot_enter_instance + CannotActionItemSecure = 1015, // cannot_action_item_secure + RaidCantnotRequiredLevel = 1016, // raid_cantnot_required_level + RaidTargetInvalidateFaction = 1017, // raid_target_invalidate_faction + NotReadySwapItem = 1018, // not_ready_swap_item + RaidJointFailedStatusChanged = 1019, // raid_joint_failed_status_changed + MailDeletedBySystem = 1020, // mail_deleted_by_system + ExpeditionDismissInSiegeOrReady = 1021, // expedition_dismiss_in_siege_or_ready + ExpeditionOwnerCannotChangeDuringSiegeOrReady = 1022, // expedition_owner_cannot_change_during_siege_or_ready + CharacterDeleteExpeditionJoined = 1023, // character_delete_expedition_joined + CharacterDeleteNationJoined = 1024, // character_delete_nation_joined + AuctionCanNotBuyDirectPrice = 1025, // auction_can_not_buy_direct_price + CannotEquipForCooldown = 1026, // cannot_equip_for_cooldown + AucPartialBuyPostMinCount = 1027, // auc_partial_buy_post_min_count + AucPartialBuyPostCannotStack = 1028, // auc_partial_buy_post_cannot_stack + AucPartialBuyDirectMoney = 1029, // auc_partial_buy_direct_money + AucPartialBuyStackCount = 1030, // auc_partial_buy_stack_count + AucPartialBuy = 1031, // auc_partial_buy + ExpeditionImmigrationInSiegeOrReady = 1032, // expedition_immigration_in_siege_or_ready + CannotLootWhileGliding = 1033, // cannot_loot_while_gliding + ExpeditionsIsFullInNation = 1034, // expeditions_is_full_in_nation + CannotOneAndOneChatWithTarget = 1035, // cannot_one_and_one_chat_with_target + AlreadyHasOneAndOneChat = 1036, // already_has_one_and_one_chat + AucPartitionLowMoney = 1037, // auc_partition_low_money + ImmigrationExpeditionsIsFullInNation = 1038, // immigration_expeditions_is_full_in_nation + BeautyshopSpecChanged = 1039, // beautyshop_spec_changed + CraftOrderNeedDelay = 1040, // craft_order_need_delay + CraftOrderLimit = 1041, // craft_order_limit + CraftOrderFee = 1042, // craft_order_fee + CraftOrderStatus = 1043, // craft_order_status + CraftNotOrderable = 1044, // craft_not_orderable + MateCannotOverlapSummonHere = 1045, // mate_cannot_overlap_summon_here + SlaveEquipCooldownInBattle = 1046, // slave_equip_cooldown_in_battle + CannotUseInTrial = 1047, // cannot_use_in_trial + CannotSiegeauctionWithFullExpeditionAndDominion = 1048, // cannot_siegeauction_with_full_expedition_and_dominion + CannotTeamChatWithRaidLink = 1049, // cannot_team_chat_with_raid_link + ChatNotInSquad = 1050, // chat_not_in_squad + CanNotDyeOfSlaveWhenSummonedSlave = 1051, // can_not_dye_of_slave_when_summoned_slave + CanNotSummonSlaveDuringSlaveDyeing = 1052, // can_not_summon_slave_during_slave_dyeing + CanNotDyeOfSlaveWhenSlaveReleasing = 1053, // can_not_dye_of_slave_when_slave_releasing + WrongDyeingColor = 1054, // wrong_dyeing_color + CannotEquipSlotBecauseRechargeBuff = 1055, // cannot_equip_slot_because_recharge_buff + SquadInviteNotAuthorized = 1056, // squad_invite_not_authorized + BattleFieldDivisionNotMatch = 1057, // battle_field_division_not_match + SquadFull = 1058, // squad_full + SquadAlreadyMember = 1059, // squad_already_member + CancleDyeing = 1060, // cancle_dyeing + CanNotDyeingThisItem = 1061, // can_not_dyeing_this_item + TargetIsDestroyedAndCanNotDye = 1062, // target_is_destroyed_and_can_not_dye + CanNotDyeInTheCurrentStateOfTheTarget = 1063, // can_not_dye_in_the_current_state_of_the_target + SquadMemberNotFound = 1064, // squad_member_not_found + SquadNeedWorldName = 1065, // squad_need_world_name + RecruitVolunteerInvitationRefused = 1066, // recruit_volunteer_invitation_refused + ZonePermissionWithInstance = 1067, // zone_permission_with_instance + AlreadyHasSquad = 1068, // already_has_squad + InvalidSquad = 1069, // invalid_squad + SquadFullJoinFailed = 1070, // squad_full_join_failed + SquadPermissionDenied = 1071, // squad_permission_denied + SquadCannotPerformThisAction = 1072, // squad_cannot_perform_this_action + SquadCannotJoinThis = 1073, // squad_cannot_join_this + OptionSkillAlertSaveSuccess = 1074, // option_skill_alert_save_success + OptionSkillAlertSaveCancel = 1075, // option_skill_alert_save_cancel + CofferCannotPutInCoffer = 1076, // coffer_cannot_put_in_coffer + CannotJoinTeamWhileApplyingBattlefield = 1077, // cannot_join_team_while_applying_battlefield + CannotTeamInviteAutoRefuse = 1078, // cannot_team_invite_auto_refuse + CannotEnterBattleFieldNow = 1079, // cannot_enter_battle_field_now + ItemNotBankStorable = 1080, // item_not_bank_storable + CannotInviteWhoInIndun = 1081, // cannot_invite_who_in_indun + CanNotDyeOfSlaveWhenSummoningSlave = 1083 // can_not_dye_of_slave_when_summoning_slave } diff --git a/AAEmu.Game/Models/Game/Gimmicks/Gimmick.cs b/AAEmu.Game/Models/Game/Gimmicks/Gimmick.cs index 914a3fda86..6dcd81bfec 100644 --- a/AAEmu.Game/Models/Game/Gimmicks/Gimmick.cs +++ b/AAEmu.Game/Models/Game/Gimmicks/Gimmick.cs @@ -125,7 +125,7 @@ public void StopMovement() return; var caster = WorldManager.Instance.GetNpc(SpawnerUnitId); - var skillCaster = SkillCaster.GetByType(SkillCasterType.Doodad); + var skillCaster = SkillCaster.GetByType(SkillCasterType.Gimmick); skillCaster.ObjId = this.ObjId; var skillCastTarget = SkillCastTarget.GetByType(SkillCastTargetType.Position); diff --git a/AAEmu.Game/Models/Game/Housing/House.cs b/AAEmu.Game/Models/Game/Housing/House.cs index 5689160339..e7cc02bbe3 100644 --- a/AAEmu.Game/Models/Game/Housing/House.cs +++ b/AAEmu.Game/Models/Game/Housing/House.cs @@ -325,6 +325,20 @@ public PacketStream Write(PacketStream stream) stream.Write(ExpandedDecoLimit); // expandedDecoLimit stream.Write(Template.MainModelId); // model_id (type) не точно! stream.Write(IsPublic); // isPublic + // add in 5+ + for (var i = 0; i < 5; i++) + { + stream.Write(0u); // houseId + stream.Write(0L); // type + stream.Write(0); // ucc_kind + stream.Write(0); // ucc_positon + } + stream.Write(Helpers.ConvertLongX(Transform.World.Position.X - 10)); + stream.Write(Helpers.ConvertLongY(Transform.World.Position.Y - 10)); + stream.Write(Transform.World.Position.Z); + stream.Write(Helpers.ConvertLongX(Transform.World.Position.X + 10)); + stream.Write(Helpers.ConvertLongY(Transform.World.Position.Y + 10)); + stream.Write(Transform.World.Position.Z); return stream; } diff --git a/AAEmu.Game/Models/Game/Items/Actions/AAPointUpdate.cs b/AAEmu.Game/Models/Game/Items/Actions/AAPointUpdate.cs index b56c55bb64..0510d82300 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/AAPointUpdate.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/AAPointUpdate.cs @@ -10,6 +10,7 @@ public AAPointUpdate(int amount) { _type = ItemAction.ChangeAaPoint; // 16 _amount = amount; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ChangeAutoUseAAPoint.cs b/AAEmu.Game/Models/Game/Items/Actions/ChangeAutoUseAAPoint.cs index 5bbe363ac2..9f77e45127 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ChangeAutoUseAAPoint.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ChangeAutoUseAAPoint.cs @@ -8,8 +8,9 @@ public class ChangeAutoUseAAPoint : ItemTask public ChangeAutoUseAAPoint(byte change) { - _change = change; _type = ItemAction.ChangeAutoUseAaPoint; // 18 + _change = change; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ChangeBankAAPoint.cs b/AAEmu.Game/Models/Game/Items/Actions/ChangeBankAAPoint.cs index df3b86e4cc..4c452a806f 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ChangeBankAAPoint.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ChangeBankAAPoint.cs @@ -10,6 +10,7 @@ public ChangeBankAAPoint(int amount) { _type = ItemAction.ChangeBankAaPoint; // 17 _amount = amount; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ChangeGamePoint.cs b/AAEmu.Game/Models/Game/Items/Actions/ChangeGamePoint.cs index b42a2a1f4e..776d60d6aa 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ChangeGamePoint.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ChangeGamePoint.cs @@ -9,9 +9,10 @@ public class ChangeGamePoint : ItemTask public ChangeGamePoint(byte kind, int amount) { + _type = ItemAction.ChangeGamePoint; // 3 _amount = amount; _kind = kind; - _type = ItemAction.ChangeGamePoint; // 3 + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemAction.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemAction.cs index f31a2cd121..9da7bd289d 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemAction.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemAction.cs @@ -21,5 +21,5 @@ public enum ItemAction ChangeAaPoint = 16, ChangeBankAaPoint = 17, ChangeAutoUseAaPoint = 18, - UpdateChargeUseSkillTime = 19, + UpdateChargeUseSkillTime = 19 } diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemAdd.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemAdd.cs index 77d904c922..e82eba06a7 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemAdd.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemAdd.cs @@ -10,6 +10,7 @@ public ItemAdd(Item item) { _type = ItemAction.Create; // 5 _item = item; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) @@ -19,22 +20,7 @@ public override PacketStream Write(PacketStream stream) stream.Write((byte)_item.SlotType); stream.Write((byte)_item.Slot); - stream.Write(_item.TemplateId); - stream.Write(_item.Id); - stream.Write(_item.Grade); - stream.Write(_item.Flags); - stream.Write(_item.Count); - stream.Write((byte)_item.DetailType); - - _item.WriteDetails(stream); - - stream.Write(_item.CreateTime); - stream.Write(_item.LifespanMins); - stream.Write(_item.MadeUnitId); - stream.Write(_item.WorldId); - stream.Write(_item.UnsecureTime); - stream.Write(_item.UnpackTime); - stream.Write(_item.ChargeUseSkillTime); + stream.Write(_item); return stream; } diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemAddNew.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemAddNew.cs index ed32d7f6ad..dae5cee394 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemAddNew.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemAddNew.cs @@ -8,8 +8,9 @@ public class ItemAddNew : ItemTask public ItemAddNew(Item item) { - _item = item; _type = ItemAction.ChangeOwner; // 15 + _item = item; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) @@ -19,27 +20,7 @@ public override PacketStream Write(PacketStream stream) stream.Write((byte)_item.SlotType); stream.Write((byte)_item.Slot); - stream.Write(_item.TemplateId); - stream.Write(_item.Id); - stream.Write(_item.Grade); - stream.Write((byte)0); - stream.Write(_item.Count); - - var details = new PacketStream(); - details.Write((byte)_item.DetailType); - - _item.WriteDetails(details); - - stream.Write((short)128); - stream.Write(details, false); - stream.Write(new byte[128 - details.Count]); - stream.Write(_item.CreateTime); - stream.Write(_item.LifespanMins); - stream.Write(_item.MadeUnitId); - stream.Write(_item.WorldId); - stream.Write(_item.UnsecureTime); - stream.Write(_item.UnpackTime); - stream.Write(_item.ChargeUseSkillTime); + stream.Write(_item); return stream; } diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemBuyback.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemBuyback.cs index ea0f626ba1..9adf4ba75a 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemBuyback.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemBuyback.cs @@ -10,14 +10,18 @@ public ItemBuyback(Item item) { _type = ItemAction.Take; // 6 _item = item; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) { base.Write(stream); - stream.Write((byte)_item.SlotType); // type - stream.Write((byte)_item.Slot); // index - _item.Write(stream); + + stream.Write((byte)_item.SlotType); + stream.Write((byte)_item.Slot); + + stream.Write(_item); + return stream; } } diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemCountUpdate.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemCountUpdate.cs index cacbe942e1..6b465d8331 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemCountUpdate.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemCountUpdate.cs @@ -17,6 +17,7 @@ public ItemCountUpdate(Item item, int count) _type = ItemAction.AddStack; // 4 _item = item; _count = count; + _tLogt = SetTlogT(_type, SlotType.Bag, _count < 0); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemGradeChange.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemGradeChange.cs index 5668ac359e..0b081d4008 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemGradeChange.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemGradeChange.cs @@ -9,9 +9,10 @@ public class ItemGradeChange : ItemTask public ItemGradeChange(Item item, byte newGrade) { + _type = ItemAction.ChangeGrade; // 14 _item = item; _grade = newGrade; - _type = ItemAction.ChangeGrade; // 14 + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemMove.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemMove.cs index 0786100db2..c5f886db7a 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemMove.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemMove.cs @@ -20,6 +20,9 @@ public ItemMove(SlotType fromSlotType, byte fromSlot, ulong fromItemId, SlotType _toSlotType = toSlotType; _toSlot = toSlot; _toItemId = toItemId; + _tLogt = SetTlogT(_type, fromSlotType == toSlotType ? + SlotType.Bag : // установим tLogt по значению ItemAction, предмет в одном месте + SlotType.Bank); // установим tLogt по значению ItemAction, предмет в разных местах } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemRemove.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemRemove.cs index 61f306eae5..184a4a7d50 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemRemove.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemRemove.cs @@ -6,7 +6,8 @@ namespace AAEmu.Game.Models.Game.Items.Actions; public class ItemRemove : ItemTask { - private readonly ulong _itemId; + private readonly Item _item; + private readonly ulong _Id; private readonly byte _slotType; private readonly byte _slot; private readonly uint _templateId; @@ -16,40 +17,23 @@ public class ItemRemove : ItemTask public ItemRemove(Item item) { _type = ItemAction.Remove; // 7 - - _itemId = item.Id; - _slotType = (byte)item.SlotType; - _slot = (byte)item.Slot; - _templateId = item.TemplateId; - _removeReservationTime = DateTime.MinValue; - _itemCount = item.Count; - } - - public ItemRemove(ulong itemId, SlotType slotType, byte slotNumber, uint itemTemplateId) - { - _type = ItemAction.Remove; // 7 - - _itemId = itemId; - _slotType = (byte)slotType; - _slot = slotNumber; - _templateId = itemTemplateId; + _item = item; _removeReservationTime = DateTime.MinValue; - _itemCount = 1; - + _tLogt = SetTlogT(_type, item.SlotType, _itemCount < 0); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) { base.Write(stream); - stream.Write(_slotType); // type - stream.Write(_slot); // index - stream.Write(_itemId); // id - stream.Write(_itemCount); // stack + stream.Write((byte)_item.SlotType); // type + stream.Write((byte)_item.Slot); // index + stream.Write(_item.Id); // id + stream.Write(_item.Count); // stack stream.Write(_removeReservationTime); // removeReservationTime - stream.Write(_templateId); // type - stream.Write(0u); // dbSlaveId stream.Write(0u); // type + stream.Write(0u); // dbSlaveId + stream.Write(_item.TemplateId); // type return stream; } diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemRemoveCrafting.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemRemoveCrafting.cs index bc4ff27676..d839d87d82 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemRemoveCrafting.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemRemoveCrafting.cs @@ -8,8 +8,9 @@ public class ItemRemoveCrafting : ItemTask public ItemRemoveCrafting(ulong id) { - _id = id; _type = ItemAction.RemoveCrafting; // 12 + _id = id; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemRemoveSlot.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemRemoveSlot.cs index 79c0aea79f..319b290f84 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemRemoveSlot.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemRemoveSlot.cs @@ -15,6 +15,7 @@ public ItemRemoveSlot(Item item) _itemId = item.Id; _slotType = item.SlotType; _slot = (byte)item.Slot; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public ItemRemoveSlot(ulong itemId, SlotType slotType, byte slot) @@ -24,6 +25,7 @@ public ItemRemoveSlot(ulong itemId, SlotType slotType, byte slot) _itemId = itemId; _slotType = slotType; _slot = slot; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemTask.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemTask.cs index 0cfc302d32..50a23e1210 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemTask.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemTask.cs @@ -1,15 +1,88 @@ -using AAEmu.Commons.Network; +using System; + +using AAEmu.Commons.Network; namespace AAEmu.Game.Models.Game.Items.Actions; public abstract class ItemTask : PacketMarshaler { protected ItemAction _type; + protected ItemTaskLogType _tLogt; public override PacketStream Write(PacketStream stream) { stream.Write((byte)_type); // tasks - stream.Write((byte)0); // tLogt + stream.Write((byte)_tLogt); // tLogt return stream; } + + public ItemTaskLogType SetTlogT(ItemAction itemTask, SlotType slotType, bool added = true) + { + var tlogT = ItemTaskLogType.UpdateOnly; + switch (itemTask) + { + case ItemAction.Invalid: // 0 + break; + case ItemAction.ChangeMoneyAmount: // 1 + tlogT = ItemTaskLogType.UpdateOnly; + break; + case ItemAction.ChangeBankMoneyAmount: // 2 + tlogT = ItemTaskLogType.UpdateOnly; + break; + case ItemAction.ChangeGamePoint: // 3 + tlogT = ItemTaskLogType.UpdateOnly; + break; + case ItemAction.AddStack when added == true: // 4 + tlogT = ItemTaskLogType.MoveItem; // если добавили + break; + case ItemAction.AddStack when added == false: // 4 + tlogT = ItemTaskLogType.RemoveItem; // если убавили + break; + case ItemAction.Create: // 5 + tlogT = ItemTaskLogType.GainItem; + break; + case ItemAction.Take: // 6 + tlogT = ItemTaskLogType.MoveItem; + break; + case ItemAction.Remove when slotType == SlotType.Bag: // 7 + tlogT = ItemTaskLogType.RemoveItem; + break; + case ItemAction.Remove when slotType == SlotType.Equipment: // 7 + tlogT = ItemTaskLogType.Place; + break; + case ItemAction.SwapSlot when slotType == SlotType.Bank: // 8 + tlogT = ItemTaskLogType.MoveItem; + break; + case ItemAction.SwapSlot when slotType == SlotType.Bag: // 8 + tlogT = ItemTaskLogType.SwapItem; + break; + case ItemAction.UpdateDetail: // 9 + tlogT = ItemTaskLogType.UpdateOnly; + break; + case ItemAction.SetFlagsBits: // 10 + break; + case ItemAction.UpdateFlags: // 11 + break; + case ItemAction.RemoveCrafting: // 12 + break; + case ItemAction.Seize: // 13 + break; + case ItemAction.ChangeGrade: // 14 + break; + case ItemAction.ChangeOwner: // 15 + break; + case ItemAction.ChangeAaPoint: // 16 + break; + case ItemAction.ChangeBankAaPoint: // 17 + break; + case ItemAction.ChangeAutoUseAaPoint: // 18 + break; + case ItemAction.UpdateChargeUseSkillTime: // 19 + break; + default: + throw new ArgumentOutOfRangeException(nameof(itemTask), itemTask, null); + } + + return tlogT; + } } diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemTaskLogType.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemTaskLogType.cs new file mode 100644 index 0000000000..b1ce9811b1 --- /dev/null +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemTaskLogType.cs @@ -0,0 +1,9 @@ +public enum ItemTaskLogType : byte +{ + UpdateOnly = 0, + GainItem = 1, + RemoveItem = 2, + MoveItem = 3, + SwapItem = 4, + Place = 5 +} diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemTaskType.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemTaskType.cs index 3405611af2..a3542c57e6 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemTaskType.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemTaskType.cs @@ -3,122 +3,183 @@ // TODO at X2::GameClient::ApplyItemTaskToSelf public enum ItemTaskType : byte { - Invalid = 0, - Destroy = 1, - AboxDestroy = 2, - Repair = 3, - DurabilityLoss = 4, - SwapItems = 5, - Split = 6, - SplitCofferItems = 7, - SwapCofferItems = 8, - Loot = 9, - LootAll = 10, - Gm = 11, - GameRuleReset = 12, - ConsumeSkillSource = 13, // 303-consume-skill-source - DoodadCreate = 14, // 303-doodad-create - DoodadRemove = 15, - DoodadItemChanger = 16, - DoodadInteraction = 17, - DoodadCattleFeed = 18, - UpgradeSkill = 19, - AbilityChange = 20, - AbilityReset = 21, - BuyPriestBuff = 22, - Teleport = 23, - CapturePet = 24, - RecoverDoodadItem = 25, // 508-recover-doodad-item - MateCreate = 26, - CraftActSaved = 27, - CraftPaySaved = 28, - CraftPickupProduct = 29, - CraftCancel = 30, - HouseCreation = 31, // 303-house-creation - HouseDeposit = 32, - HouseBuilding = 33, - PickupBloodstain = 34, - AutoLootDoodadItem = 35, // 316-autoloot-doodad-item - QuestStart = 36, // 401-quest-start - QuestComplete = 37, // 402-quest-complete - QuestSupplyItems = 38, // 405-quest-supply-items - QuestRemoveSupplies = 39, // 402-403-404-405-quest-remove-supplies - SkillReagents = 40, - SkillEffectConsumption = 41, - SkillEffectGainItem = 42, - SkillEffectGainItemWithPos = 43, - SkillEffectSiegeTicket = 44, - SkillEffectExpToItem = 45, - Auction = 46, - Mail = 47, - Trade = 48, - EnchantMagical = 49, - EnchantPhysical = 50, - GetCoinByItem = 51, - GetItemByCoin = 52, - StoreSell = 53, // 315-store-sell - StoreBuy = 54, // 313-314-store-buy - TodReward = 55, - GainItemWithUcc = 56, - ImprintUcc = 57, - RepairPets = 58, - MateDeath = 59, - Shipyard = 60, // 303-shipyard - SkillsReset = 61, - DropBackpack = 62, - UseRelic = 63, - UseIndependenceRelic = 64, - Conversion = 65, // 304-conversion - Seize = 66, - ReturnSeized = 67, - DemoDressOff = 68, - DemoDressOn = 69, - DemoClearBag = 70, - DemoFillBag = 71, - SlaveDeath = 72, - ExpeditionCreation = 73, - RepairSlaves = 74, - ExpandBag = 75, - ExpandBank = 76, - RenewEquipment = 77, - LifespanExpiration = 78, - RecoverExp = 79, - SpawnerUpdate = 80, - UpdateSummonSlaveItem = 81, - UpdateSummonMateItem = 82, - DepositMoney = 83, - WithdrawMoney = 84, - DeliverItemToOthers = 85, - SetSlavePosition = 86, - SetBountyMoney = 87, - PayBountyMoney = 88, - ConvertFish = 89, - Fishing = 90, - SellHouse = 91, - BuyHouse = 92, - SaveMusicNotes = 93, - ItemLock = 94, - ItemUnlock = 95, - ItemUnlockExcess = 96, - GradeEnchant = 97, - RechargeBuff = 98, - Socketing = 99, - Dyeing = 100, - ConsumeIndunTicket = 101, - ExpandExpert = 102, - Exchange = 103, - SellBackpack = 104, - SellSpecialty = 105, - AskMould = 106, - TakeMould = 107, - FactionDeclareHostile = 108, - EditCosmetic = 109, - ChangeAutoUseAaPoint = 110, - ConvertItemLook = 111, - ChangeExpertLimit = 112, - Sknize = 113, - ItemTaskThistimeUnpack = 114, - BuyPremiumService = 115, - BuyAaPoint = 116, - Unk136 = 136 + // updated to version 5.0.7.0 + Invalid = 0, // invalid + Destroy = 1, // destroy + AboxDestroy = 2, // abox-destroy + Repair = 3, // repair + DurabilityLoss = 4, // durability-loss + SwapItems = 5, // swap-items + Split = 6, // split + SplitCofferItems = 7, // split-coffer-items + SwapCofferItems = 8, // swap-coffer-items + Loot = 9, // loot + LootAll = 10, // loot-all + Gm = 11, // gm + GameRuleReset = 12, // gamerule-reset + ConsumeSkillSource = 13, // 303-consume-skill-source + DoodadCreate = 14, // 303-doodad-create + DoodadRemove = 15, // doodad-remove + DoodadItemChanger = 16, // doodad-item_changer + DoodadInteraction = 17, // doodad-interaction + DoodadCattleFeed = 18, // doodad-cattle-feed + // UpgradeSkill = 19 + AbilityChange = 19, // ability-change + AbilityReset = 20, // ability-reset + // BuyPriestBuff = 22 + // Teleport = 23 + CapturePet, // capture-pet + RecoverDoodadItem, // 508-recover-doodad-item + MateCreate, // mate-create + CraftActSaved, // craft-act-saved + CraftPaySaved, // craft-pay-saved + CraftPickupProduct = 27, // craft-pickup-product + CraftCancel, // craft-cancel + MakeCraftOrderSheet, // make-craft-order-sheet + RestoreCraftOrderSsheet, // restore-craft-order-sheet + PostCcraftOrder, // post-craft-order + HouseCreation = 32, // 303-house-creation + HouseDeposit, // house-deposit + HouseBuilding = 34, // house-building + PickupBloodstain, // pickup-bloodstain + AutoLootDoodadItem, // 316-autoloot-doodad-item + QuestStart = 37, // 401-quest-start + QuestComplete = 38, // 402-quest-complete + QuestSupplyItems, // 405-quest-supply-items + QuestRemoveSupplies, // 402-403-404-405-quest-remove-supplies + SkillReagents, // skill-reagents + SkillEffectConsumption, // skill-effect-consumption + SkillEffectGainItem, // skill-effect-gain-item + SkillEffectGainItemWithPos, // skill-effect-gain-item-with-pos + SkillEffectSiegeTicket, // skill-effect-siege-ticket + SkillEffectExpToItem, // skill-effect-exp-to-item + Auction = 48, // auction + Mail = 49, // mail + Trade, // trade + EnchantMagical, // enchant-magical + EnchantPhysical, // enchant-physical + GetCoinByItem, // get-coin-by-item + GetItemByCoin, // get-item-from-doodad + StoreSell = 55, // 315-store-sell + StoreBuy = 56, // 313-314-store-buy + TodReward, // tod-reward + CreateOriginUcc, // create-origin-ucc + MakeUccDdye, // make-ucc-dye + // GainItemWithUcc = 56 + ImprintUcc = 60, // imprint-ucc + RepairPets, // repair-pets + MateDeath = 62, // mate-death + Shipyard = 63, // 303-shipyard + SkillsReset, // skills-reset + DropBackpack = 65, // drop-backpack + UseRelic, // use-relic + UseIndependenceRelic, // use-independence-relic + Conversion = 68, // 304-conversion + Seize, // seize + ReturnSeized, // return-seized + DemoDressOff, // demo-dress-off + DemoDressOn, // demo-dress-on + DemoClearBag, // demo-clear-bag + DemoFillBag, // demo-fill-bag + SlaveDeath = 75, // slave-death + ExpeditionCreation, // expedition-creation + DeclareExpeditionWar, // declare-expedition-war + RecruitmentDecMoney, // recruitment-dec-money + RepairSlaves, // repair-slaves + ExpandBag, // expand-bag + ExpandBank, // expand-bank + // RenewEquipment = 77 + LifespanExpiration = 83, // lifespan-expiration + RecoverExp, // recover-exp + SpawnerUpdate, // spawner_update + UpdateSummonSlaveItem = 86, // update-summon-slave-item + UpdateSummonMateItem = 87, // update-summon-mate-item + DepositMoney = 88, // deposit-money + WithdrawMoney, // withdraw-money + DeliverItemToOthers, // deliver-item-to-others + SetSlavePosition, // set-slave-position + SetBountyMoney, // set-bounty-money + PayBountyMoney, // pay-bounty-money + ConvertFish, // convert-fish + Fishing, // fishing + SellHouse, // sell-house + BuyHouse, // buy-house + SaveMusicNotes, // save-music-notes + ItemLock, // item-lock + ItemUnlock, // item-unlock + ItemUnlockExcess, // item-unlockexcess + GradeEnchant, // grade-enchant + ShipGradeEnchant, // ship-grade-enchant + RechargeRndAttrUnitModifier, // recharge-rnd-attr-unit-modifier + RechargeBuff, // recharge-buff + Socketing, // socketing + Evolving, // evolving + Smelting, // smelting + Dyeing, // dyeing + RechargeItemProcLifetime, // recharge-item-proc-lifetime + ConsumeIndunTicket, // consume-indun-ticket + ExpandExpert, // expand-expert + Exchange, // exchange + SellBackpack, // sell-backpack + SellSpecialty, // sell-specialty + BuySpecialty, // buy-specialty + AskMould, // ask-mould + TakeMould, // take-mould + FactionDeclareHostile, // faction-declare-hostile + EditCosmetic, // edit-cosmetic + ChangeAutoUseAaPoint, // change-auto-use-aa-point + ConvertItemLook, // convert_item_look + RevertItemLook, // revert_item_look + ChangeExpertLimit, // change-expert-limit + Sknize, // sknize + ItemTaskThistimeUnpack, // item-task-thistime-unpack + BuyPremiumService, // buy-premium-service-ingameshop + BuyAaPoint, // buy-aa-point-ingameshop + TakeScheduleItem, // take-schedule-item + ScaleCap, // scale-cap + HousePayTax, // house-pay-tax + BuyItemIngameshop, // buy-item-ingameshop + ExchangeCashFromItem, // exchange-cash-from-item + RepairSlaveEquipment, // repair-slave-equipment + RechargeSkill, // recharge-skill + AchievementSupplyItems, // achievement-supply-items + TodayAssignmentUnlock, // today-assignment-unlock + HouseRebuild, // house-rebuild + ItemTaskResurrectionInPlace, // item-task-resurrection-in-place + TodayAssignmentSupplyItems, // today-assignment-supply-items + ItemTaskBattleCoin, // item-task-battle-coin + GiveRewardItem, // give-reward-item + ExchangeAapointFromCash, // exchange-aapoint-from-cash + SpendItemFromChat, // spend-item-from-chat + ItemTaskRemoveHeroReward, // = 143,// item-task-remove-hero-reward + ExpeditionSummon, // expedition-summon + MateRevive, // mate-revive + ExpandAbilitySetSlot, // expand-ability-set-slot + QuestCompleteBalance, // 402-quest-complete-balance + ExpandDecoLimit, // expand-deco-limit + HouseDemolish, // house_demolish + SiegeAuction, // siege-auction + SelectiveItem, // selective-item + NationRequestFriend, // nation_request_friend + DoodadOneshotPlace, // doodad-oneshot-place + NationDelegate, // nation-delegate + RenameFaction, // rename-faction + BlessUthstinInitStats, // bless-uthstin-init-stats + BlessUthstinChangeStats, // bless-uthstin-change-stats + BlessUthstinExpandMaxStats, // bless-uthstin-expand-max-stats + BlessUthstinExpandPage, // bless-uthstin-expand-page + BlessUthstinSelectPage, // bless-uthstin-select-page + BlessUthstinCopyPage, // bless-uthstin-copy-page + FamilyJoin, // family-join + FamilyLeave, // family-leave + FamilyKick, // family-kick + FamilyIncMember, // family-inc-member + FamilyChangeName, // family-change-name + HeirSkillReset, // heir-skill-reset + SlaveFollow, // slave_follow + RaidRecruit, // raid-recruit + RestoreDisableEnchant, // restore-disable-enchant + ConsumeEquipSlotReinforceLevelUp,// consume-equip-slot-reinforce-level-up + ConsumeEquipSlotReinforceAddExp, // consume-equip-slot-reinforce-add-exp + ItemTypeChange // item_type_change } diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemUpdate.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemUpdate.cs index 7826399118..263e978422 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemUpdate.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemUpdate.cs @@ -10,6 +10,7 @@ public ItemUpdate(Item item) { _type = ItemAction.UpdateDetail; // 9 _item = item; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) @@ -22,7 +23,6 @@ public override PacketStream Write(PacketStream stream) var details = new PacketStream(); details.Write((byte)_item.DetailType); - //details.Write(0u); // добавил для нормальной работы починки предметов _item.WriteDetails(details); diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateBits.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateBits.cs index 8d773e37d0..9ed87409c7 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateBits.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateBits.cs @@ -19,6 +19,7 @@ public ItemUpdateBits(Item item) // 10 image // 20 unwrapp //_oldBits = oldBits; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateRepair.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateRepair.cs index a65868a645..3a2e2ced82 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateRepair.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateRepair.cs @@ -10,6 +10,7 @@ public ItemUpdateRepair(Item item) { _type = ItemAction.UpdateDetail; // 9 _item = item; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateSecurity.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateSecurity.cs index bbb61f97cb..dfe7425dfe 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateSecurity.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemUpdateSecurity.cs @@ -12,12 +12,13 @@ public class ItemUpdateSecurity : ItemTask public ItemUpdateSecurity(Item item, byte bits, bool isUnsecureExcess, bool isUnsecureSet, bool isUnpack) { + _type = ItemAction.UpdateFlags; // 11 _item = item; _bits = bits; _isUnsecureExcess = isUnsecureExcess; _isUnsecureSet = isUnsecureSet; _isUnpack = isUnpack; - _type = ItemAction.UpdateFlags; // 11 + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/MoneyChange.cs b/AAEmu.Game/Models/Game/Items/Actions/MoneyChange.cs index 07c4d244f1..c5f4b88482 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/MoneyChange.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/MoneyChange.cs @@ -10,6 +10,8 @@ public MoneyChange(int amount) { _type = ItemAction.ChangeMoneyAmount; // 1 _amount = amount; + _tLogt = SetTlogT(_type, SlotType.Bag, _amount < 0); // установим tLogt по значению ItemAction + } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Models/Game/Items/Actions/UpdateChargeUseSkillTime.cs b/AAEmu.Game/Models/Game/Items/Actions/UpdateChargeUseSkillTime.cs index e5e2e9772f..06fddf5a2f 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/UpdateChargeUseSkillTime.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/UpdateChargeUseSkillTime.cs @@ -17,6 +17,7 @@ public UpdateChargeUseSkillTime(Item item, int count) _type = ItemAction.UpdateChargeUseSkillTime; // 19 _item = item; _count = count; + _tLogt = SetTlogT(_type, SlotType.Bag); // установим tLogt по значению ItemAction } public override PacketStream Write(PacketStream stream) @@ -24,7 +25,7 @@ public override PacketStream Write(PacketStream stream) base.Write(stream); stream.Write((byte)_item.SlotType); // type stream.Write((byte)_item.Slot); // index - stream.Write(_item.Id); // id + stream.Write(_item.Id); // itemId stream.Write(_item.ChargeUseSkillTime); // chargeUseSkillTime return stream; } diff --git a/AAEmu.Game/Models/Game/Items/AuctionSettings.cs b/AAEmu.Game/Models/Game/Items/AuctionSettings.cs new file mode 100644 index 0000000000..f876392c2f --- /dev/null +++ b/AAEmu.Game/Models/Game/Items/AuctionSettings.cs @@ -0,0 +1,19 @@ +namespace AAEmu.Game.Models.Game.Items; + +public class AuctionSettings +{ + public int CategoryA; + public int CategoryB; + public int CategoryC; + public uint AuctionCharge; + public bool AuctionChargeDefault; + + public AuctionSettings(int categoryA, int categoryB, int categoryC, uint auctionCharge, bool auctionChargeDefault) + { + CategoryA = categoryA; + CategoryB = categoryB; + CategoryC = categoryC; + AuctionCharge = auctionCharge; + AuctionChargeDefault = auctionChargeDefault; + } +} diff --git a/AAEmu.Game/Models/Game/Items/Containers/CofferContainer.cs b/AAEmu.Game/Models/Game/Items/Containers/CofferContainer.cs index ec5dc592f4..b6aaa6638e 100644 --- a/AAEmu.Game/Models/Game/Items/Containers/CofferContainer.cs +++ b/AAEmu.Game/Models/Game/Items/Containers/CofferContainer.cs @@ -9,7 +9,7 @@ public class CofferContainer : ItemContainer public byte CofferPermission { get; set; } public ChestType CofferType { get; set; } - public CofferContainer(uint ownerId, bool createWithNewId) : base(ownerId, SlotType.Trade, createWithNewId, null) + public CofferContainer(uint ownerId, bool createWithNewId) : base(ownerId, SlotType.Coffer, createWithNewId, null) { // Coffers are considered trade windows in the item manipulation code CofferPermission = 0; diff --git a/AAEmu.Game/Models/Game/Items/Containers/EquipmentContainer.cs b/AAEmu.Game/Models/Game/Items/Containers/EquipmentContainer.cs index d3ddf0e73d..0160ba0303 100644 --- a/AAEmu.Game/Models/Game/Items/Containers/EquipmentContainer.cs +++ b/AAEmu.Game/Models/Game/Items/Containers/EquipmentContainer.cs @@ -159,7 +159,7 @@ public override bool CanAccept(Item item, int targetSlot) if (Owner == null) return true; // Not applicable to NPCs, they can hold whatever they want anywhere - if (item.SlotType == SlotType.EquipmentSlave) + if (item.SlotType == SlotType.SlaveEquipment) return true; // they can hold whatever they want anywhere if (item.Template.ImplId == ItemImplEnum.SlaveEquipment) diff --git a/AAEmu.Game/Models/Game/Items/Containers/ItemContainer.cs b/AAEmu.Game/Models/Game/Items/Containers/ItemContainer.cs index b23264afa8..11d806e38d 100644 --- a/AAEmu.Game/Models/Game/Items/Containers/ItemContainer.cs +++ b/AAEmu.Game/Models/Game/Items/Containers/ItemContainer.cs @@ -100,15 +100,17 @@ public ulong ContainerId private bool PartOfPlayerInventory => ContainerType switch { - SlotType.None => false, + SlotType.Invalid => false, SlotType.Equipment => true, - SlotType.Inventory => true, + SlotType.Bag => true, SlotType.Bank => true, - SlotType.Trade => true, - SlotType.Mail => false, - SlotType.System => false, - SlotType.EquipmentMate => false, - SlotType.EquipmentSlave => false, + SlotType.Coffer => true, + SlotType.MailAttachment => false, + SlotType.Money => false, + SlotType.PetRideEquipment => false, + SlotType.SlaveEquipment => false, + SlotType.StoreGood => false, + SlotType.Auction => false, _ => throw new ArgumentOutOfRangeException() }; @@ -133,7 +135,7 @@ protected ItemContainer() { // Only relevant for inheritance Owner = null; - ContainerType = SlotType.None; + ContainerType = SlotType.Invalid; Items = new List(); ContainerSize = 0; } @@ -336,7 +338,7 @@ public bool AddOrMoveExistingItem(ItemTaskType taskType, Item item, int preferre // Make sure the item is in container size's range if ( - ContainerType == SlotType.Inventory && item.Template.MaxCount > 1 && + ContainerType == SlotType.Bag && item.Template.MaxCount > 1 && currentPreferredSlotItem != null && currentPreferredSlotItem.TemplateId == item.TemplateId && currentPreferredSlotItem.Grade == item.Grade && item.Count + currentPreferredSlotItem.Count <= item.Template.MaxCount) @@ -369,7 +371,7 @@ public bool AddOrMoveExistingItem(ItemTaskType taskType, Item item, int preferre if (canAddToSameSlot) { currentPreferredSlotItem.Count += item.Count; - if (ContainerType != SlotType.None) + if (ContainerType != SlotType.Invalid) { itemTasks.Add(new ItemCountUpdate(currentPreferredSlotItem, item.Count)); } @@ -380,14 +382,13 @@ public bool AddOrMoveExistingItem(ItemTaskType taskType, Item item, int preferre item.Slot = newSlot; item._holdingContainer = this; item.OwnerId = OwnerId; - sourceContainer = item._holdingContainer; Items.Insert(0, item); // insert at front for easy buyback handling UpdateFreeSlotCount(); // Note we use SlotType.None for things like the Item BuyBack Container. Make sure to manually handle the remove for these - if (ContainerType != SlotType.None) + if (ContainerType != SlotType.Invalid) { itemTasks.Add(new ItemAdd(item)); } @@ -404,7 +405,7 @@ public bool AddOrMoveExistingItem(ItemTaskType taskType, Item item, int preferre { sourceContainer.Items.Remove(item); sourceContainer.UpdateFreeSlotCount(); - if (sourceContainer.ContainerType != SlotType.Mail) + if (sourceContainer.ContainerType != SlotType.MailAttachment) { sourceItemTasks.Add(new ItemRemoveSlot(item.Id, sourceSlotType, sourceSlot)); } @@ -428,20 +429,20 @@ public bool AddOrMoveExistingItem(ItemTaskType taskType, Item item, int preferre // Moved to the end of the method so that the item is already in the inventory // Only trigger when moving between containers with different owners except for this being move to Mail container - //if ((sourceContainer != this) && (item.OwnerId != OwnerId) && (this.ContainerType != SlotType.Mail)) - if (sourceContainer != this && ContainerType != SlotType.Mail) + //if ((sourceContainer != this) && (item.OwnerId != OwnerId) && (this.ContainerType != SlotType.MailAttachment)) + if (sourceContainer != this && ContainerType != SlotType.MailAttachment) { Owner?.Inventory.OnAcquiredItem(item, item.Count); } else // Got attachment from Mail - if (item.SlotType == SlotType.Mail && ContainerType != SlotType.Mail) + if (item.SlotType == SlotType.MailAttachment && ContainerType != SlotType.MailAttachment) { Owner?.Inventory.OnAcquiredItem(item, item.Count); } else // Adding mail attachment - if (item.SlotType != SlotType.Mail && ContainerType == SlotType.Mail) + if (item.SlotType != SlotType.MailAttachment && ContainerType == SlotType.MailAttachment) { Owner?.Inventory.OnConsumedItem(item, item.Count); } @@ -656,7 +657,7 @@ public bool AcquireDefaultItemEx(ItemTaskType taskType, uint templateId, int amo var itemTasks = new List(); // Never update in mail containers - if (ContainerType != SlotType.Mail) + if (ContainerType != SlotType.MailAttachment) { foreach (var i in currentItems) { @@ -831,6 +832,7 @@ public bool GetAllItemsByTemplate(uint templateId, int gradeToFind, out List 0; } + public bool GetAllItemsByTemplate(uint templateId, out List foundItems, out int unitsOfItemFound) { foundItems = new List(); @@ -854,7 +856,7 @@ public void ApplyBindRules(ItemTaskType taskType) { if (item.HasFlag(ItemFlag.SoulBound) == false) { - if (ContainerType == SlotType.Inventory && item.Template.BindType == ItemBindType.BindOnPickup) + if (ContainerType == SlotType.Bag && item.Template.BindType == ItemBindType.BindOnPickup) { item.SetFlag(ItemFlag.SoulBound); } @@ -915,8 +917,7 @@ public virtual bool CanAccept(Item item, int targetSlot) /// /// Actual unit that will hold this container /// - public static ItemContainer CreateByTypeName(string containerTypeName, uint ownerId, SlotType slotType, - bool createWithNewId, Unit parentUnit) + public static ItemContainer CreateByTypeName(string containerTypeName, uint ownerId, SlotType slotType, bool createWithNewId, Unit parentUnit) { if (containerTypeName.EndsWith("SlaveEquipmentContainer")) return new SlaveEquipmentContainer(ownerId, slotType, createWithNewId, parentUnit); @@ -958,11 +959,18 @@ public virtual void Delete() public virtual void OnEnterContainer(Item item, ItemContainer lastContainer, byte previousSlot) { - // Do nothing + item._holdingContainer = this; // назначим новый контейнер + //item.SlotType = ContainerType; + //item.Slot = previousSlot; + item.OwnerId = OwnerId; } public virtual void OnLeaveContainer(Item item, ItemContainer newContainer, byte previousSlot) { // Do Nothing + //item._holdingContainer = null; // назначим новый контейнер + //item.SlotType = SlotType.Invalid; + //item.Slot = previousSlot; + //item.OwnerId = OwnerId; } } diff --git a/AAEmu.Game/Models/Game/Items/Containers/SlaveEquipmentContainer.cs b/AAEmu.Game/Models/Game/Items/Containers/SlaveEquipmentContainer.cs index cd680e0bab..643263e531 100644 --- a/AAEmu.Game/Models/Game/Items/Containers/SlaveEquipmentContainer.cs +++ b/AAEmu.Game/Models/Game/Items/Containers/SlaveEquipmentContainer.cs @@ -1,7 +1,6 @@ using System; using System.Linq; -using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Units; namespace AAEmu.Game.Models.Game.Items.Containers @@ -14,56 +13,56 @@ public SlaveEquipmentContainer(uint ownerId, SlotType containerType, bool create ContainerSize = (int)Enum.GetValues(typeof(EquipmentItemSlot)).Cast().Max() + 1; } - public override void OnEnterContainer(Item item, ItemContainer lastContainer, byte previousSlot) - { - base.OnEnterContainer(item, lastContainer, previousSlot); // base EquipmentContainer + //public override void OnEnterContainer(Item item, ItemContainer lastContainer, byte previousSlot) + //{ + // base.OnEnterContainer(item, lastContainer, previousSlot); // base EquipmentContainer - // Extra pockets for slaves - if (ParentUnit is not Units.Slave slave) - { - return; - } + // // Extra pockets for slaves + // if (ParentUnit is not Units.Slave slave) + // { + // return; + // } - var slaveItem = new ItemAndLocation - { - Item = item, - SlotType = lastContainer.ContainerType, // ContainerType, - SlotNumber = previousSlot, - }; - var inventoryItem = new ItemAndLocation - { - Item = null, - SlotType = ContainerType, - SlotNumber = (byte)item.Slot, - }; - // Owner.SendMessage($"SlaveEquipmentContainer - {slaveItem} -> {inventoryItem}, SlaveTl: {slave.TlId}"); - Owner.SendPacket(new SCSlaveEquipmentChangedPacket(slaveItem, inventoryItem, slave.TlId, Owner.Id, 0, false, true, DateTime.MinValue)); - } + // var slaveItem = new ItemAndLocation() + // { + // Item = null, + // SlotType = item.SlotType, // newContainer + // SlotNumber = (byte)item.Slot, + // }; + // var inventoryItem = new ItemAndLocation() + // { + // Item = item, + // SlotType = ContainerType, + // SlotNumber = previousSlot, + // }; + // // Owner.SendMessage($"SlaveEquipmentContainer - {slaveItem} -> {inventoryItem}, SlaveTl: {slave.TlId}"); + // //Owner.SendPacket(new SCSlaveEquipmentChangedPacket(slaveItem, inventoryItem, slave.TlId, Owner.Id, 0, false, true, DateTime.MinValue)); + //} - public override void OnLeaveContainer(Item item, ItemContainer newContainer, byte previousSlot) - { - base.OnLeaveContainer(item, newContainer, previousSlot); // base EquipmentContainer + //public override void OnLeaveContainer(Item item, ItemContainer newContainer, byte previousSlot) + //{ + // base.OnLeaveContainer(item, newContainer, previousSlot); // base EquipmentContainer - // Extra pockets for slaves - if (ParentUnit is not Units.Slave slave) - { - return; - } + // // Extra pockets for slaves + // if (ParentUnit is not Units.Slave slave) + // { + // return; + // } - var slaveItem = new ItemAndLocation() - { - Item = null, - SlotType = item.SlotType, // newContainer - SlotNumber = (byte)item.Slot, - }; - var inventoryItem = new ItemAndLocation() - { - Item = item, - SlotType = ContainerType, - SlotNumber = previousSlot, - }; - // Owner.SendMessage($"SlaveEquipmentContainer - {slaveItem} -> {inventoryItem}, SlaveTl: {slave.TlId}"); - Owner.SendPacket(new SCSlaveEquipmentChangedPacket(slaveItem, inventoryItem, slave.TlId, Owner.Id, 0, false, true, DateTime.MinValue)); - } + // var slaveItem = new ItemAndLocation() + // { + // Item = null, + // SlotType = item.SlotType, // newContainer + // SlotNumber = (byte)item.Slot, + // }; + // var inventoryItem = new ItemAndLocation() + // { + // Item = item, + // SlotType = ContainerType, + // SlotNumber = previousSlot, + // }; + // // Owner.SendMessage($"SlaveEquipmentContainer - {slaveItem} -> {inventoryItem}, SlaveTl: {slave.TlId}"); + // //Owner.SendPacket(new SCSlaveEquipmentChangedPacket(slaveItem, inventoryItem, slave.TlId, Owner.Id, 0, false, true, DateTime.MinValue)); + //} } } diff --git a/AAEmu.Game/Models/Game/Items/Item.cs b/AAEmu.Game/Models/Game/Items/Item.cs index 715f4bcc23..489d998038 100644 --- a/AAEmu.Game/Models/Game/Items/Item.cs +++ b/AAEmu.Game/Models/Game/Items/Item.cs @@ -1,6 +1,5 @@ using System; using System.Linq; - using AAEmu.Commons.Network; using AAEmu.Game.Models.Game.Items.Containers; using AAEmu.Game.Models.Game.Items.Templates; @@ -118,14 +117,14 @@ public ulong UccId // Helper public ItemContainer _holdingContainer { get; set; } - public static uint Coins { get; } = 500; - public static uint TaxCertificate { get; } = 31891; - public static uint BoundTaxCertificate { get; } = 31892; - public static uint AppraisalCertificate { get; } = 28085; - public static uint CrestStamp { get; } = 17662; - public static uint CrestInk { get; } = 17663; - public static uint SheetMusic { get; } = 28051; - public static uint SalonCertificate { get; } = 30811; + public static uint Coins => 500; + public static uint TaxCertificate => 31891; + public static uint BoundTaxCertificate => 31892; + public static uint AppraisalCertificate => 28085; + public static uint CrestStamp => 17662; + public static uint CrestInk => 17663; + public static uint SheetMusic => 28051; + public static uint SalonCertificate => 30811; /// /// Sort will use itemSlot numbers @@ -336,7 +335,7 @@ public virtual void WriteDetails(PacketStream stream) stream.Write(TemperMagical); // scaledB stream.Write(ChargeProcTime); // chargeProcTime stream.Write(MappingFailBonus); // mappingFailBonus - нет в 4.5.2.6, есть в 4.5.1.0 и 5.7 - + var gemIds = GemIds.Select(id => (long)id).ToArray(); stream.WritePiscW(gemIds.Length, gemIds); //stream.WritePisc(GemIds[0], GemIds[1], GemIds[2], GemIds[3]); diff --git a/AAEmu.Game/Models/Game/Items/Loots/LootPack.cs b/AAEmu.Game/Models/Game/Items/Loots/LootPack.cs index 661de59d4c..898985821a 100644 --- a/AAEmu.Game/Models/Game/Items/Loots/LootPack.cs +++ b/AAEmu.Game/Models/Game/Items/Loots/LootPack.cs @@ -206,7 +206,7 @@ public bool GiveLootPack(Character character, ItemTaskType taskType, List<(uint if (itemTemplateId == Item.Coins) { // Logger.Debug("{Category} - {Character} got {Amount} from lootpack {Lootpack}"); - character.AddMoney(SlotType.Inventory, count, taskType); + character.AddMoney(SlotType.Bag, count, taskType); continue; } diff --git a/AAEmu.Game/Models/Game/Items/SlotType.cs b/AAEmu.Game/Models/Game/Items/SlotType.cs index bd4ffb9c5c..9e6c80ccf6 100644 --- a/AAEmu.Game/Models/Game/Items/SlotType.cs +++ b/AAEmu.Game/Models/Game/Items/SlotType.cs @@ -2,45 +2,35 @@ public enum SlotType : byte { - None = 0, - Equipment = 1, - Inventory = 2, - Bank = 3, - Trade = 4, - Mail = 5, - EquipmentSlave = 242, - EquipmentMate = 252, - System = 0xFF - - //Invalid = 0, - //Equipment = 1, - //Bag = 2, - //Bank = 3, - //Coffer = 4, - //Seized = 5, - //Auction = 6, - //Mountable = 64, - //Mountable1Bag = 65, - //Mountable2Bag = 66, - //ShortcutAction = 235, - //ContributionPoint = 236, - //PetBattleEquipment = 237, - //PetBattleCommand = 238, - //PetBattleAction = 239, - //AutoUseAaPoint = 240, - //AaPoint = 241, - //SlaveEquipment = 242, - //AbilityView = 243, - //InstantKillStreak = 244, - //LivingPoint = 245, - //ModeAction = 246, - //PetRideCommand = 247, - //PetRideAction = 248, - //Constant = 249, - //HonorPoint = 250, - //StoreGood = 251, - //PetRideEquipment = 252, - //MailAttachment = 253, - //Action = 254, - //Money = 0xFF + Invalid = 0, // None = 0 + Equipment = 1, // Equipment = 1, + Bag = 2, // Inventory = 2, + Bank = 3, // Bank = 3, + Coffer = 4, // Trade = 4, + Seized = 5, + Auction = 6, + Mountable = 64, + Mountable1Bag = 65, + Mountable2Bag = 66, + ShortcutAction = 235, + ContributionPoint = 236, + PetBattleEquipment = 237, + PetBattleCommand = 238, + PetBattleAction = 239, + AutoUseAaPoint = 240, + AaPoint = 241, + SlaveEquipment = 242, + AbilityView = 243, + InstantKillStreak = 244, + LivingPoint = 245, + ModeAction = 246, + PetRideCommand = 247, + PetRideAction = 248, + Constant = 249, + HonorPoint = 250, + StoreGood = 251, + PetRideEquipment = 252, // EquipmentMate = 252, + MailAttachment = 253, // Mail = 5, + Action = 254, + Money = 0xFF // System = 0xFF } diff --git a/AAEmu.Game/Models/Game/Items/SummonMate.cs b/AAEmu.Game/Models/Game/Items/SummonMate.cs index 19ac68f629..6d51433c11 100644 --- a/AAEmu.Game/Models/Game/Items/SummonMate.cs +++ b/AAEmu.Game/Models/Game/Items/SummonMate.cs @@ -24,19 +24,20 @@ public override void ReadDetails(PacketStream stream) if (stream.LeftBytes < DetailBytesLength) return; DetailMateExp = stream.ReadInt32(); // exp - _ = stream.ReadByte(); // unk = 0 - DetailLevel = stream.ReadByte(); // level - _ = stream.ReadBytes(14); // unknown + _ = stream.ReadByte(); // unk = 0 + DetailLevel = stream.ReadByte(); // level + _ = stream.ReadBytes(14); // unknown } public override void WriteDetails(PacketStream stream) { stream.Write(DetailMateExp); // exp - stream.Write((byte)0); // unk = 0 - stream.Write(DetailLevel); // level - stream.Write(new byte[14]); // add up to 20 - } + stream.Write((byte)0); + stream.Write(DetailLevel); // level + stream.Write(new byte[14]); // add up to 20 + } + public override void OnManuallyDestroyingItem() { base.OnManuallyDestroyingItem(); diff --git a/AAEmu.Game/Models/Game/Items/Templates/ItemTemplate.cs b/AAEmu.Game/Models/Game/Items/Templates/ItemTemplate.cs index 260c7ed4a5..45b88b0cb5 100644 --- a/AAEmu.Game/Models/Game/Items/Templates/ItemTemplate.cs +++ b/AAEmu.Game/Models/Game/Items/Templates/ItemTemplate.cs @@ -42,7 +42,13 @@ public class ItemTemplate public int LivingPointPrice { get; set; } public byte CharGender { get; set; } public uint SpecialtyZoneId { get; set; } + public AuctionSettings AuctionSettings { get; set; } // Helpers public string searchString { get; set; } + + public ItemTemplate() + { + AuctionSettings = new AuctionSettings(0, 0, 0, 0, true); // Инициализация AuctionSettings + } } diff --git a/AAEmu.Game/Models/Game/Mails/BaseMail.cs b/AAEmu.Game/Models/Game/Mails/BaseMail.cs index b626d66332..d198fb3952 100644 --- a/AAEmu.Game/Models/Game/Mails/BaseMail.cs +++ b/AAEmu.Game/Models/Game/Mails/BaseMail.cs @@ -4,6 +4,7 @@ using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Items; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; @@ -112,7 +113,7 @@ protected void RenumberSlots() { for (var i = 0; i < Body.Attachments.Count; i++) { - Body.Attachments[i].SlotType = SlotType.Mail; + Body.Attachments[i].SlotType = SlotType.MailAttachment; Body.Attachments[i].Slot = i; } } diff --git a/AAEmu.Game/Models/Game/Mails/CommercialMail.cs b/AAEmu.Game/Models/Game/Mails/CommercialMail.cs index b0c1baa157..128db3cf56 100644 --- a/AAEmu.Game/Models/Game/Mails/CommercialMail.cs +++ b/AAEmu.Game/Models/Game/Mails/CommercialMail.cs @@ -3,6 +3,7 @@ using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; @@ -39,7 +40,7 @@ public CommercialMail(uint receiverId, string receiverName, string senderName, L _purchasedItemTitle = purchasedItemTitle; MailType = MailType.Charged; - Header.SenderId = 0; + Header.SenderId = (uint)SystemMailSenderKind.IngameShop; Header.SenderName = InGameCashShopSenderName; // Name changes depending on type of mail ReceiverName = receiverName; Header.ReceiverId = _receiverId; diff --git a/AAEmu.Game/Models/Game/Mails/CountUnreadMail.cs b/AAEmu.Game/Models/Game/Mails/CountUnreadMail.cs index a83c3372d3..02f4183c9e 100644 --- a/AAEmu.Game/Models/Game/Mails/CountUnreadMail.cs +++ b/AAEmu.Game/Models/Game/Mails/CountUnreadMail.cs @@ -1,4 +1,5 @@ using AAEmu.Commons.Network; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; @@ -42,17 +43,30 @@ public void UpdateReceived(MailType mailType, int amount) if (mailType is MailType.Charged or MailType.Promotion) { TotalCommercialReceived += amount; - UnreadCommercialReceived += amount; } else if (mailType == MailType.MiaRecv) { TotalMiaReceived += amount; - UnreadMiaReceived += amount; } else { TotalReceived += amount; + } + } + public void UpdateUnreadReceived(MailType mailType, int amount) + { + if (mailType is MailType.Charged or MailType.Promotion) + { + UnreadCommercialReceived += amount; + } + else + if (mailType == MailType.MiaRecv) + { + UnreadMiaReceived += amount; + } + else + { UnreadReceived += amount; } } diff --git a/AAEmu.Game/Models/Game/Mails/MailBody.cs b/AAEmu.Game/Models/Game/Mails/MailBody.cs index 0ee026c630..f6e9e89c54 100644 --- a/AAEmu.Game/Models/Game/Mails/MailBody.cs +++ b/AAEmu.Game/Models/Game/Mails/MailBody.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using AAEmu.Commons.Network; using AAEmu.Game.Models.Game.Items; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; diff --git a/AAEmu.Game/Models/Game/Mails/MailForAuction.cs b/AAEmu.Game/Models/Game/Mails/MailForAuction.cs index 4f0c5658cd..5e3d776121 100644 --- a/AAEmu.Game/Models/Game/Mails/MailForAuction.cs +++ b/AAEmu.Game/Models/Game/Mails/MailForAuction.cs @@ -1,6 +1,8 @@ using System; + using AAEmu.Game.Core.Managers; using AAEmu.Game.Models.Game.Items; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; @@ -38,9 +40,10 @@ public MailForAuction(Item itemToSell, uint sellerId, int buyoutPrice, int listi // Correct types and name will be set in finalize functions MailType = MailType.InvalidMailType; - Header.SenderId = 0; + Header.SenderId = (uint)SystemMailSenderKind.None; Header.SenderName = AuctionName; // Name changes depending on type of mail + Body.SendDate = DateTime.UtcNow; Body.RecvDate = DateTime.UtcNow; // These mails should always be instant } @@ -64,9 +67,10 @@ public MailForAuction(uint itemTemplateIdToSell, uint sellerId, int buyoutPrice, // Correct types and name will be set in finalize functions MailType = MailType.InvalidMailType; - Header.SenderId = 0; + Header.SenderId = (uint)SystemMailSenderKind.None; Header.SenderName = AuctionName; // Name changes depending on type of mail + Body.SendDate = DateTime.UtcNow; Body.RecvDate = DateTime.UtcNow; // These mails should always be instant } @@ -92,7 +96,7 @@ public bool FinalizeForSaleBuyer(uint buyerId) Body.Text = string.Format("body('{0}', {1}, {2})", _itemName, _item.Count, _itemBuyoutPrice); _item.OwnerId = _buyerId; - _item.SlotType = SlotType.Mail; + _item.SlotType = SlotType.MailAttachment; Body.Attachments.Add(_item); return true; @@ -148,7 +152,7 @@ public bool FinalizeForCancel() Body.Text = string.Format("body('{0}', {1})", _itemName, _item.Count); _item.OwnerId = _sellerId; - _item.SlotType = SlotType.Mail; + _item.SlotType = SlotType.MailAttachment; Body.Attachments.Add(_item); return true; @@ -175,7 +179,7 @@ public bool FinalizeForFail() Body.Text = string.Format("body('{0}', {1})", _itemName, _item.Count); _item.OwnerId = _sellerId; - _item.SlotType = SlotType.Mail; + _item.SlotType = SlotType.MailAttachment; Body.Attachments.Add(_item); return true; diff --git a/AAEmu.Game/Models/Game/Mails/MailForSpeciality.cs b/AAEmu.Game/Models/Game/Mails/MailForSpeciality.cs index 6c0853f6bc..417bd7e906 100644 --- a/AAEmu.Game/Models/Game/Mails/MailForSpeciality.cs +++ b/AAEmu.Game/Models/Game/Mails/MailForSpeciality.cs @@ -2,6 +2,7 @@ using AAEmu.Game.Core.Managers; using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Items; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; @@ -108,7 +109,7 @@ public bool FinalizeForSeller() if (itemTemplate == null) return false; - Header.SenderId = 0; + Header.SenderId = (uint)SystemMailSenderKind.None; Header.SenderName = TradeDeliveryName; Header.ReceiverId = _sender.Id; @@ -145,7 +146,7 @@ public bool FinalizeForSeller() itemGrade = 0; var newItem = ItemManager.Instance.Create(_itemToSend, _itemCountSeller, (byte)itemGrade, true); newItem.OwnerId = _sender.Id; - newItem.SlotType = SlotType.Mail; + newItem.SlotType = SlotType.MailAttachment; Body.Attachments.Add(newItem); // Body.Text = "Placeholder resource delivery text body"; @@ -182,7 +183,7 @@ public bool FinalizeForCrafter() if (itemTemplate == null) return false; - Header.SenderId = 0; + Header.SenderId = (uint)SystemMailSenderKind.None; Header.SenderName = TradeDeliveryName; Header.ReceiverId = _crafterId; @@ -221,7 +222,7 @@ public bool FinalizeForCrafter() itemGrade = 0; var newItem = ItemManager.Instance.Create(_itemToSend, _itemCountCrafter, (byte)itemGrade, true); newItem.OwnerId = _sender.Id; - newItem.SlotType = SlotType.Mail; + newItem.SlotType = SlotType.MailAttachment; Body.Attachments.Add(newItem); Body.Text = string.Format("body('{0}', {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9})", diff --git a/AAEmu.Game/Models/Game/Mails/MailForTax.cs b/AAEmu.Game/Models/Game/Mails/MailForTax.cs index 4f5fbddcb5..9b5645731c 100644 --- a/AAEmu.Game/Models/Game/Mails/MailForTax.cs +++ b/AAEmu.Game/Models/Game/Mails/MailForTax.cs @@ -3,6 +3,7 @@ using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Models.Game.Housing; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; @@ -91,7 +92,7 @@ public static bool UpdateTaxInfo(BaseMail mail, House house) /// public bool FinalizeMail() { - Header.SenderId = 0; + Header.SenderId = (uint)SystemMailSenderKind.None; Header.SenderName = TaxSenderName; if (!UpdateTaxInfo(this, _house)) diff --git a/AAEmu.Game/Models/Game/Mails/MailHeader.cs b/AAEmu.Game/Models/Game/Mails/MailHeader.cs index 42ea164884..b4b9a434ad 100644 --- a/AAEmu.Game/Models/Game/Mails/MailHeader.cs +++ b/AAEmu.Game/Models/Game/Mails/MailHeader.cs @@ -1,5 +1,6 @@ using System; using AAEmu.Commons.Network; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; diff --git a/AAEmu.Game/Models/Game/Mails/MailPlayerToPlayer.cs b/AAEmu.Game/Models/Game/Mails/MailPlayerToPlayer.cs index ef40beb03f..5fbeef7480 100644 --- a/AAEmu.Game/Models/Game/Mails/MailPlayerToPlayer.cs +++ b/AAEmu.Game/Models/Game/Mails/MailPlayerToPlayer.cs @@ -4,6 +4,7 @@ using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; @@ -62,7 +63,7 @@ public bool PrepareAttachmentItems(List<(SlotType, byte)> itemSlotsForMail) if (mailSlots.Item1 != 0) { var tempItem = _sender.Inventory.GetItem(mailSlots.Item1, mailSlots.Item2); - if ((tempItem == null) || (tempItem.SlotType != SlotType.Inventory)) + if ((tempItem == null) || (tempItem.SlotType != SlotType.Bag)) { // Attchment Items do not match player inventory, abort return false; @@ -88,7 +89,7 @@ public bool FinalizeAttachments() { _sender.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.Mail, new List() { new ItemRemove(tempItem) }, new List())); // Technically not needed, I just want to sync it up - tempItem.SlotType = SlotType.Mail; + tempItem.SlotType = SlotType.MailAttachment; tempItem.Slot = i; // tempItem.OwnerId = mailTemplate.Header.ReceiverId; } diff --git a/AAEmu.Game/Models/Game/Mails/CommercialMailTypes.cs b/AAEmu.Game/Models/Game/Mails/Static/CommercialMailTypes.cs similarity index 77% rename from AAEmu.Game/Models/Game/Mails/CommercialMailTypes.cs rename to AAEmu.Game/Models/Game/Mails/Static/CommercialMailTypes.cs index cce37974a2..d4d5400747 100644 --- a/AAEmu.Game/Models/Game/Mails/CommercialMailTypes.cs +++ b/AAEmu.Game/Models/Game/Mails/Static/CommercialMailTypes.cs @@ -1,4 +1,4 @@ -namespace AAEmu.Game.Models.Game.Mails; +namespace AAEmu.Game.Models.Game.Mails.Static; public enum CommercialMailTypes { diff --git a/AAEmu.Game/Models/Game/Mails/Static/MailBoxListKind.cs b/AAEmu.Game/Models/Game/Mails/Static/MailBoxListKind.cs new file mode 100644 index 0000000000..15faabc3d2 --- /dev/null +++ b/AAEmu.Game/Models/Game/Mails/Static/MailBoxListKind.cs @@ -0,0 +1,10 @@ +namespace AAEmu.Game.Models.Game.Mails.Static; + +public enum MailBoxListKind +{ + None = 0, + Inbox = 1, + Outbox = 2, + Commercial = 3, + Mia = 4 +} diff --git a/AAEmu.Game/Models/Game/Mails/MailResult.cs b/AAEmu.Game/Models/Game/Mails/Static/MailResult.cs similarity index 97% rename from AAEmu.Game/Models/Game/Mails/MailResult.cs rename to AAEmu.Game/Models/Game/Mails/Static/MailResult.cs index 1276d8d17f..84495e13d4 100644 --- a/AAEmu.Game/Models/Game/Mails/MailResult.cs +++ b/AAEmu.Game/Models/Game/Mails/Static/MailResult.cs @@ -1,4 +1,4 @@ -namespace AAEmu.Game.Models.Game.Mails; +namespace AAEmu.Game.Models.Game.Mails.Static; // There are many repetitions with ErrorMessageType public enum MailResult : byte diff --git a/AAEmu.Game/Models/Game/Mails/MailStatus.cs b/AAEmu.Game/Models/Game/Mails/Static/MailStatus.cs similarity index 61% rename from AAEmu.Game/Models/Game/Mails/MailStatus.cs rename to AAEmu.Game/Models/Game/Mails/Static/MailStatus.cs index feb3931805..c679455404 100644 --- a/AAEmu.Game/Models/Game/Mails/MailStatus.cs +++ b/AAEmu.Game/Models/Game/Mails/Static/MailStatus.cs @@ -1,4 +1,4 @@ -namespace AAEmu.Game.Models.Game.Mails; +namespace AAEmu.Game.Models.Game.Mails.Static; public enum MailStatus : byte { diff --git a/AAEmu.Game/Models/Game/Mails/MailType.cs b/AAEmu.Game/Models/Game/Mails/Static/MailType.cs similarity index 95% rename from AAEmu.Game/Models/Game/Mails/MailType.cs rename to AAEmu.Game/Models/Game/Mails/Static/MailType.cs index 543117b3ae..b65773e9b4 100644 --- a/AAEmu.Game/Models/Game/Mails/MailType.cs +++ b/AAEmu.Game/Models/Game/Mails/Static/MailType.cs @@ -1,4 +1,4 @@ -namespace AAEmu.Game.Models.Game.Mails; +namespace AAEmu.Game.Models.Game.Mails.Static; public enum MailType : byte { diff --git a/AAEmu.Game/Models/Game/Mails/MiaMailTypes.cs b/AAEmu.Game/Models/Game/Mails/Static/MiaMailTypes.cs similarity index 65% rename from AAEmu.Game/Models/Game/Mails/MiaMailTypes.cs rename to AAEmu.Game/Models/Game/Mails/Static/MiaMailTypes.cs index 15173763ca..68c618c253 100644 --- a/AAEmu.Game/Models/Game/Mails/MiaMailTypes.cs +++ b/AAEmu.Game/Models/Game/Mails/Static/MiaMailTypes.cs @@ -1,4 +1,4 @@ -namespace AAEmu.Game.Models.Game.Mails; +namespace AAEmu.Game.Models.Game.Mails.Static; public enum MiaMailTypes { diff --git a/AAEmu.Game/Models/Game/Mails/Static/SystemMailSenderKind.cs b/AAEmu.Game/Models/Game/Mails/Static/SystemMailSenderKind.cs new file mode 100644 index 0000000000..96c489c664 --- /dev/null +++ b/AAEmu.Game/Models/Game/Mails/Static/SystemMailSenderKind.cs @@ -0,0 +1,7 @@ +namespace AAEmu.Game.Models.Game.Mails.Static; + +public enum SystemMailSenderKind +{ + None = 0, + IngameShop = 1 +} diff --git a/AAEmu.Game/Models/Game/Quests/Acts/QuestActConAcceptItem.cs b/AAEmu.Game/Models/Game/Quests/Acts/QuestActConAcceptItem.cs index f377f28fc0..391ab92b88 100644 --- a/AAEmu.Game/Models/Game/Quests/Acts/QuestActConAcceptItem.cs +++ b/AAEmu.Game/Models/Game/Quests/Acts/QuestActConAcceptItem.cs @@ -21,7 +21,7 @@ public class QuestActConAcceptItem(QuestComponentTemplate parentComponent) : Que public override bool RunAct(Quest quest, QuestAct questAct, int currentObjectiveCount) { Logger.Trace($"{QuestActTemplateName}({DetailId}).RunAct: Quest: {quest.TemplateId}, Owner {quest.Owner.Name} ({quest.Owner.Id}), ItemId {ItemId}"); - return (quest.QuestAcceptorType == QuestAcceptorType.Item) && (quest.AcceptorId == ItemId) && quest.Owner.Inventory.CheckItems(Items.SlotType.Inventory, ItemId, 1); + return (quest.QuestAcceptorType == QuestAcceptorType.Item) && (quest.AcceptorId == ItemId) && quest.Owner.Inventory.CheckItems(Items.SlotType.Bag, ItemId, 1); } public override void QuestCleanup(Quest quest) diff --git a/AAEmu.Game/Models/Game/Quests/Acts/QuestActConAcceptItemGain.cs b/AAEmu.Game/Models/Game/Quests/Acts/QuestActConAcceptItemGain.cs index b8aa3c00b6..c040817238 100644 --- a/AAEmu.Game/Models/Game/Quests/Acts/QuestActConAcceptItemGain.cs +++ b/AAEmu.Game/Models/Game/Quests/Acts/QuestActConAcceptItemGain.cs @@ -21,6 +21,6 @@ public class QuestActConAcceptItemGain(QuestComponentTemplate parentComponent) : public override bool RunAct(Quest quest, QuestAct questAct, int currentObjectiveCount) { Logger.Trace($"{QuestActTemplateName}({DetailId}).RunAct: Quest: {quest.TemplateId}, Owner {quest.Owner.Name} ({quest.Owner.Id}), ItemId {ItemId}"); - return (quest.QuestAcceptorType == QuestAcceptorType.Item) && (quest.AcceptorId == ItemId) && quest.Owner.Inventory.CheckItems(Items.SlotType.Inventory, ItemId, Count); + return (quest.QuestAcceptorType == QuestAcceptorType.Item) && (quest.AcceptorId == ItemId) && quest.Owner.Inventory.CheckItems(Items.SlotType.Bag, ItemId, Count); } } diff --git a/AAEmu.Game/Models/Game/Quests/Acts/QuestActSupplyRemoveItem.cs b/AAEmu.Game/Models/Game/Quests/Acts/QuestActSupplyRemoveItem.cs index 34cf2a4f9a..4dc72ac772 100644 --- a/AAEmu.Game/Models/Game/Quests/Acts/QuestActSupplyRemoveItem.cs +++ b/AAEmu.Game/Models/Game/Quests/Acts/QuestActSupplyRemoveItem.cs @@ -23,7 +23,7 @@ public override bool RunAct(Quest quest, QuestAct questAct, int currentObjective if (quest.Owner is Character player) { - _ = player.Inventory.GetAllItemsByTemplate(new[] { SlotType.Inventory }, ItemId, -1, out _, out var unitsCount); + _ = player.Inventory.GetAllItemsByTemplate(new[] { SlotType.Bag }, ItemId, -1, out _, out var unitsCount); var toRemove = Math.Min(unitsCount, Count); var removed = player.Inventory.ConsumeItem(null, ItemTaskType.QuestRemoveSupplies, ItemId, toRemove, null); diff --git a/AAEmu.Game/Models/Game/Quests/NewQuestCode.cs b/AAEmu.Game/Models/Game/Quests/NewQuestCode.cs index be420b55b6..8c9455a613 100644 --- a/AAEmu.Game/Models/Game/Quests/NewQuestCode.cs +++ b/AAEmu.Game/Models/Game/Quests/NewQuestCode.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using AAEmu.Game.Core.Packets.G2C; +using AAEmu.Game.Models.Game.Items.Actions; using AAEmu.Game.Models.Game.Quests.Static; using AAEmu.Game.Models.Game.Units; @@ -54,6 +55,7 @@ public bool StartQuest() // Send the first components, or the one that's used to start this ? ComponentId = stepStart.Components.Values.FirstOrDefault()?.Template.Id ?? 0; Owner.SendPacket(new SCQuestContextStartedPacket(this, ComponentId)); + Owner.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.QuestStart, [], [])); Logger.Debug($"StartQuest, Quest:{TemplateId}, Player {Owner.Name} ({Owner.Id})"); return true; } diff --git a/AAEmu.Game/Models/Game/Quests/Quest.cs b/AAEmu.Game/Models/Game/Quests/Quest.cs index ad4e70fab7..06f47cc795 100644 --- a/AAEmu.Game/Models/Game/Quests/Quest.cs +++ b/AAEmu.Game/Models/Game/Quests/Quest.cs @@ -91,6 +91,7 @@ public QuestComponentKind Step /// private int LeftTime => Time > DateTime.UtcNow ? (int)(Time - DateTime.UtcNow).TotalMilliseconds : -1; private int SupplyItem { get; set; } + public bool IsCheckSet { get; set; } /// /// DoodadId used in the Quest Packet @@ -401,7 +402,7 @@ public bool DistributeRewards(bool addBaseQuestReward) { var copper = (int)Math.Round(QuestRewardCoinsPool * QuestRewardRatio); if (copper > 0) - Owner.ChangeMoney(SlotType.None, SlotType.Inventory, copper); + Owner.ChangeMoney(SlotType.Invalid, SlotType.Bag, copper); QuestRewardCoinsPool = 0; } @@ -543,7 +544,7 @@ public override PacketStream Write(PacketStream stream) // TODO do-while, count 5 stream.WritePiscW(MaxObjectiveCount, Objectives.Select(intValue => (long)intValue).ToArray()); - stream.Write(true); // isCheckSet + stream.Write(IsCheckSet); // isCheckSet stream.WriteBc((uint)ObjId); // ObjId stream.Write(0u); // type(id) stream.WriteBc((uint)ObjId); // ObjId diff --git a/AAEmu.Game/Models/Game/ScheduleItem.cs b/AAEmu.Game/Models/Game/ScheduleItem.cs index b4d68f3197..0eb5ad79b8 100644 --- a/AAEmu.Game/Models/Game/ScheduleItem.cs +++ b/AAEmu.Game/Models/Game/ScheduleItem.cs @@ -5,16 +5,16 @@ namespace AAEmu.Game.Models.Game; public class ScheduleItem : PacketMarshaler { - public uint ItemTemplateId { get; set; } + public uint ScheduleItemId { get; set; } public byte Gave { get; set; } - public uint Acumulated { get; set; } + public uint Cumulated { get; set; } public DateTime Updated { get; set; } public override PacketStream Write(PacketStream stream) { - stream.Write(ItemTemplateId); + stream.Write(ScheduleItemId); stream.Write(Gave); - stream.Write(Acumulated); + stream.Write(Cumulated); stream.Write(Updated); return stream; } diff --git a/AAEmu.Game/Models/Game/Schedules/ScheduleItems.cs b/AAEmu.Game/Models/Game/Schedules/ScheduleItems.cs new file mode 100644 index 0000000000..9a387a266a --- /dev/null +++ b/AAEmu.Game/Models/Game/Schedules/ScheduleItems.cs @@ -0,0 +1,37 @@ +namespace AAEmu.Game.Models.Game.Schedules; + +public class ScheduleItems +{ + public uint Id { get; set; } + public bool ActiveTake { get; set; } + public uint AutoTakeDelay { get; set; } + public string DisableKeyString { get; set; } + public uint EdDay { get; set; } + public uint EdHour { get; set; } + public uint EdMin { get; set; } + public uint EdMonth { get; set; } + public uint EdYear { get; set; } + public string EnableKeyString { get; set; } + public uint GiveMax { get; set; } + public uint GiveTerm { get; set; } + public string IconPath { get; set; } + public uint ItemCount { get; set; } + public uint ItemId { get; set; } + public uint KindId { get; set; } + public uint KindValue { get; set; } + public string LabelKeyString { get; set; } + public string MailBody { get; set; } + public string MailTitle { get; set; } + public string Name { get; set; } + public bool OnAir { get; set; } + public bool ShowWhenever { get; set; } + public bool ShowWherever { get; set; } + public uint StDay { get; set; } + public uint StHour { get; set; } + public uint StMin { get; set; } + public uint StMonth { get; set; } + public uint StYear { get; set; } + public bool ToolTip { get; set; } + public bool WheneverTooltip { get; set; } + public bool WhereverTooltip { get; set; } +} diff --git a/AAEmu.Game/Models/Game/Skills/BuffConstants.cs b/AAEmu.Game/Models/Game/Skills/BuffConstants.cs index bdf96e2b0a..18f7b8c0a0 100644 --- a/AAEmu.Game/Models/Game/Skills/BuffConstants.cs +++ b/AAEmu.Game/Models/Game/Skills/BuffConstants.cs @@ -18,6 +18,7 @@ public enum BuffConstants : uint Retribution = 2167, RemovalDebuff = 2250, // for houses LoggedOn = 2423, // player is logging in + Dash = 2675, Deterioration = 3553, // Deterioration TaxProtection = 3554, // Tax Protection EquipDualwield = 4899, @@ -31,5 +32,5 @@ public enum BuffConstants : uint SearchSchoolOfFish = 5736, Overburdened = 831, // SustainBuff - Carrying heavy objects reduces movement speed and prevents teleporting or gliding. MasterOwnership = 4867 // Vehicle ownership buff, prevents non-owners from attaching to the vehicle. - // Overburdened = 7221 + // Overburdened = 7221 } diff --git a/AAEmu.Game/Models/Game/Skills/Buffs/ManaRegenTemplate.cs b/AAEmu.Game/Models/Game/Skills/Buffs/ManaRegenTemplate.cs new file mode 100644 index 0000000000..1119fb9181 --- /dev/null +++ b/AAEmu.Game/Models/Game/Skills/Buffs/ManaRegenTemplate.cs @@ -0,0 +1,65 @@ +using System; + +using AAEmu.Game.Models.Game.Char; + +using NLog; + +namespace AAEmu.Game.Models.Game.Skills.Buffs; + +public class ManaRegenTemplate +{ + private static Logger Logger { get; } = LogManager.GetCurrentClassLogger(); + public Character Owner { get; set; } + private double Tick { get; set; } // Интервал тика баффа в миллисекундах + private double TickLevelManaCost { get; set; } // Стоимость маны за тик на уровне 1 + private int Level { get; set; } // Уровень персонажа + private double PreciseMana { get; set; } // Точное значение маны (если реализовано) + + public ManaRegenTemplate(Character owner, double tick, double tickLevelManaCost, int level, double preciseMana = 0) + { + Owner = owner; + Tick = tick; + TickLevelManaCost = tickLevelManaCost; + Level = level; + PreciseMana = preciseMana; + } + + // Расчет потребления маны за тик в зависимости от уровня + private double CalculateManaCostPerTick() + { + // Формула для расчета потребления маны за тик + //var manaPerTick = TickLevelManaCost * Level; + var manaPerTick = 3.33 * Level + 11.67; + return manaPerTick; + } + + // Расчет потребления маны в секунду + private double CalculateManaCostPerSecond() + { + var manaPerTick = CalculateManaCostPerTick(); + var manaPerSecond = manaPerTick * 5; // Перевод миллисекунд в секунды + return manaPerSecond; + } + + // Метод для применения баффа с учетом потребления маны + public bool ApplyBuff(Character character) + { + var manaPerTick = CalculateManaCostPerTick(); + //var manaPerSecond = CalculateManaCostPerSecond(); + + // Проверка, может баффа уже нет + if (!character.Buffs.CheckBuff((uint)BuffConstants.Dash)) + return false; + // Проверка на достаточность маны + if (character.Mp >= manaPerTick) + { + // Уменьшение маны за тик + character.ReduceCurrentMp(null, (int)manaPerTick); + return true; + } + + // Если маны недостаточно, бафф не применяется + //Logger.Debug("Not enough mana to apply the buff."); + return false; + } +} diff --git a/AAEmu.Game/Models/Game/Skills/Effects/CleanupUccEffect.cs b/AAEmu.Game/Models/Game/Skills/Effects/CleanupUccEffect.cs index 8448d4c613..d7c7c5151e 100644 --- a/AAEmu.Game/Models/Game/Skills/Effects/CleanupUccEffect.cs +++ b/AAEmu.Game/Models/Game/Skills/Effects/CleanupUccEffect.cs @@ -38,7 +38,7 @@ public override void Apply(BaseUnit caster, SkillCaster casterObj, BaseUnit targ // Send Item Ucc changed packet player.SendPacket(new SCItemUccDataChangedPacket(0, player.Id, targetItem.Id)); // Send ItemTask to change flags on client - player.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.GainItemWithUcc, new ItemUpdateBits(targetItem), null)); + player.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.CreateOriginUcc, new ItemUpdateBits(targetItem), null)); // Consume the Bleach //bleachItem._holdingContainer.ConsumeItem(ItemTaskType.ImprintUcc, bleachItem.TemplateId,1, bleachItem); } diff --git a/AAEmu.Game/Models/Game/Skills/Effects/ImprintUccEffect.cs b/AAEmu.Game/Models/Game/Skills/Effects/ImprintUccEffect.cs index d31cf9b022..2f1421b169 100644 --- a/AAEmu.Game/Models/Game/Skills/Effects/ImprintUccEffect.cs +++ b/AAEmu.Game/Models/Game/Skills/Effects/ImprintUccEffect.cs @@ -40,7 +40,7 @@ public override void Apply(BaseUnit caster, SkillCaster casterObj, BaseUnit targ // Send Item Ucc changed packet player.SendPacket(new SCItemUccDataChangedPacket(stampItem.UccId, player.Id, targetItem.Id)); // Send ItemTask to change flags on client - player.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.GainItemWithUcc, new ItemUpdateBits(targetItem), null)); + player.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.CreateOriginUcc, new ItemUpdateBits(targetItem), null)); // Consume the stamp // Retail seems to use QuestRemoveSupplies (39) for this instead of ImprintUcc //stampItem._holdingContainer.ConsumeItem(ItemTaskType.ImprintUcc, stampItem.TemplateId,1, stampItem); diff --git a/AAEmu.Game/Models/Game/Skills/Effects/ImpulseEffect.cs b/AAEmu.Game/Models/Game/Skills/Effects/ImpulseEffect.cs index 1d819c4335..6d2f518744 100644 --- a/AAEmu.Game/Models/Game/Skills/Effects/ImpulseEffect.cs +++ b/AAEmu.Game/Models/Game/Skills/Effects/ImpulseEffect.cs @@ -1,6 +1,8 @@ using System; +using System.Numerics; using AAEmu.Game.Core.Packets; +using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Skills.Templates; using AAEmu.Game.Models.Game.Units; @@ -27,6 +29,14 @@ public override void Apply(BaseUnit caster, SkillCaster casterObj, BaseUnit targ CastAction castObj, EffectSource source, SkillObject skillObject, DateTime time, CompressedGamePackets packetBuilder = null) { - Logger.Trace("ImpulseEffect"); + Logger.Debug("ImpulseEffect"); + + var vel = new Vector3(VelImpulseX, VelImpulseY, VelImpulseZ); + var angVel = new Vector3(AngvelImpulseX, AngvelImpulseY, AngvelImpulseZ); + var impulse = new Vector3(ImpulseX, ImpulseY, ImpulseZ); + var angImpulse = new Vector3(AngImpulseX, AngImpulseY, AngImpulseZ); + + caster.BroadcastPacket(new SCImpulseUnitPacket(caster.ObjId, casterObj, vel, angVel, impulse, angImpulse), true); + } } diff --git a/AAEmu.Game/Models/Game/Skills/Effects/MoveToLocationEffect.cs b/AAEmu.Game/Models/Game/Skills/Effects/MoveToLocationEffect.cs new file mode 100644 index 0000000000..45fc5c0b0c --- /dev/null +++ b/AAEmu.Game/Models/Game/Skills/Effects/MoveToLocationEffect.cs @@ -0,0 +1,37 @@ +using System; + +using AAEmu.Game.Core.Packets; +using AAEmu.Game.Core.Packets.G2C; +using AAEmu.Game.Models.Game.Char; +using AAEmu.Game.Models.Game.Skills; +using AAEmu.Game.Models.Game.Skills.Effects; +using AAEmu.Game.Models.Game.Skills.Templates; +using AAEmu.Game.Models.Game.Teleport; +using AAEmu.Game.Models.Game.Units; + +public class MoveToLocationEffect : EffectTemplate +{ + public bool OwnHouseOnly { get; set; } + + public override bool OnActionTime => false; + + public override void Apply(BaseUnit caster, SkillCaster casterObj, BaseUnit target, SkillCastTarget targetObj, + CastAction castObj, EffectSource source, SkillObject skillObject, DateTime time, + CompressedGamePackets packetBuilder = null) + { + Logger.Debug("MoveToLocationEffect"); + if (caster is Character character /*&& skillObject is SkillObjectUnk2 so*/) + { + var xyz = character.Transform.World.Position; + //character.Portals.AddPrivatePortal( + // xyz.X, + // xyz.Y, + // xyz.Z, + // character.Transform.World.Rotation.Z, + // character.Transform.ZoneId, so.Name); + + character.SendPacket(new SCUnitTeleportPacket(TeleportReason.MoveToLocation, ErrorMessageType.NoErrorMessage, xyz.X, xyz.Y, xyz.Z, character.Transform.World.Rotation.Z)); + + } + } +} diff --git a/AAEmu.Game/Models/Game/Skills/Effects/PutDownBackpackEffect.cs b/AAEmu.Game/Models/Game/Skills/Effects/PutDownBackpackEffect.cs index 66159ab914..7b528fc1fd 100644 --- a/AAEmu.Game/Models/Game/Skills/Effects/PutDownBackpackEffect.cs +++ b/AAEmu.Game/Models/Game/Skills/Effects/PutDownBackpackEffect.cs @@ -42,7 +42,7 @@ public override void Apply(BaseUnit caster, SkillCaster casterObj, BaseUnit targ var previousGlider = character.Inventory.Bag.GetItemByItemId(character.Inventory.PreviousBackPackItemId); // If no longer valid, reset the value here - if ((previousGlider == null) || (previousGlider.SlotType != SlotType.Inventory)) + if ((previousGlider == null) || (previousGlider.SlotType != SlotType.Bag)) character.Inventory.PreviousBackPackItemId = 0; using var pos = character.Transform.CloneDetached(); diff --git a/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/Blink.cs b/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/Blink.cs index 0881aeeb8a..8cbe31a6ae 100644 --- a/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/Blink.cs +++ b/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/Blink.cs @@ -46,9 +46,9 @@ public override void Execute(BaseUnit caster, } } } - character.SendPacket(new SCBlinkUnitPacket(caster.ObjId, value1, value2, newPos.Local.Position.X, newPos.Local.Position.Y, newPos.Local.Position.Z)); + character.SendPacket(new SCUnitBlinkPacket(caster.ObjId, value1, value2, newPos.Local.Position.X, newPos.Local.Position.Y, newPos.Local.Position.Z)); //character.SendMessage("To: " + newPos.ToString()); - //character.SendPacket(new SCBlinkUnitPacket(caster.ObjId, value1, value2, endX, endY, endZ)); + //character.SendPacket(new SCUnitBlinkPacket(caster.ObjId, value1, value2, endX, endY, endZ)); } } } diff --git a/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/GradeEnchant.cs b/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/GradeEnchant.cs index 4b9259535f..3d8d1ea3b3 100644 --- a/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/GradeEnchant.cs +++ b/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/GradeEnchant.cs @@ -97,7 +97,7 @@ public override void Execute(BaseUnit caster, return; } - if (!character.Inventory.CheckItems(SlotType.Inventory, scroll.ItemTemplateId, 1)) + if (!character.Inventory.CheckItems(SlotType.Bag, scroll.ItemTemplateId, 1)) { // No scroll character.SendErrorMessage(ErrorMessageType.NotEnoughRequiredItem); @@ -144,7 +144,7 @@ public override void Execute(BaseUnit caster, } // Consume - character.SubtractMoney(SlotType.Inventory, cost); + character.SubtractMoney(SlotType.Bag, cost); // TODO: Handled by skill already, do more tests // character.Inventory.PlayerInventory.ConsumeItem(ItemTaskType.GradeEnchant, scroll.ItemTemplateId, 1, character.Inventory.GetItemById(scroll.ItemId)); if (useCharm) diff --git a/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/SpawnDoodad.cs b/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/SpawnDoodad.cs index 55376ae22a..f6f4945c5c 100644 --- a/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/SpawnDoodad.cs +++ b/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/SpawnDoodad.cs @@ -54,28 +54,32 @@ int value4 } var doodad = DoodadManager.Instance.Create(0, (uint)doodadId, caster, true); - - doodad.Transform = caster.Transform.CloneDetached(doodad); - var rpy = target.Transform.World.ToRollPitchYawDegrees(); - switch (skill?.Template.TargetSelection ?? 0) + if (doodad != null) { - case SkillTargetSelection.Source: - doodad.Transform = caster.Transform.CloneDetached(doodad); - break; - case SkillTargetSelection.Target : - doodad.Transform = target.Transform.CloneDetached(doodad); - break; - case SkillTargetSelection.Line: - case SkillTargetSelection.Location: - default: - doodad.Transform = caster.Transform.CloneDetached(doodad); - break; + doodad.Transform = caster.Transform.CloneDetached(doodad); + var rpy = target.Transform.World.ToRollPitchYawDegrees(); + switch (skill?.Template.TargetSelection ?? 0) + { + case SkillTargetSelection.Source: + doodad.Transform = caster.Transform.CloneDetached(doodad); + break; + case SkillTargetSelection.Target: + doodad.Transform = target.Transform.CloneDetached(doodad); + break; + case SkillTargetSelection.Line: + case SkillTargetSelection.Location: + default: + doodad.Transform = caster.Transform.CloneDetached(doodad); + break; + } + + var (xx, yy) = MathUtil.AddDistanceToFrontDeg(1f, doodad.Transform.World.Position.X, + doodad.Transform.World.Position.Y, rpy.Z + 90f); // + 90f to Front + doodad.SetPosition(xx, yy, WorldManager.Instance.GetHeight(doodad.Transform), rpy.X, rpy.Y, rpy.Z); + doodad.InitDoodad(); + if (delay > 0) + Thread.Sleep(delay); + doodad.Spawn(); } - var (xx, yy) = MathUtil.AddDistanceToFrontDeg(1f, doodad.Transform.World.Position.X, doodad.Transform.World.Position.Y, rpy.Z + 90f); // + 90f to Front - doodad.SetPosition(xx, yy, WorldManager.Instance.GetHeight(doodad.Transform), rpy.X, rpy.Y, rpy.Z); - doodad.InitDoodad(); - if (delay > 0) - Thread.Sleep(delay); - doodad.Spawn(); } } diff --git a/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/TeleportToUnit.cs b/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/TeleportToUnit.cs index 12f53d0a29..f4c7a5e44f 100644 --- a/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/TeleportToUnit.cs +++ b/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/TeleportToUnit.cs @@ -48,7 +48,7 @@ public override void Execute(BaseUnit caster, switch (caster) { case Character character: - character.SendPacket(new SCBlinkUnitPacket(caster.ObjId, 0f, 0f, endX, endY, targetPosition.Z)); + character.SendPacket(new SCUnitBlinkPacket(caster.ObjId, 0f, 0f, endX, endY, targetPosition.Z)); break; case Npc npc: npc.MoveTowards(targetPosition, 10000); diff --git a/AAEmu.Game/Models/Game/Skills/Skill.cs b/AAEmu.Game/Models/Game/Skills/Skill.cs index 5b7d332002..29d100f5d3 100644 --- a/AAEmu.Game/Models/Game/Skills/Skill.cs +++ b/AAEmu.Game/Models/Game/Skills/Skill.cs @@ -531,6 +531,14 @@ private BaseUnit GetInitialTarget(BaseUnit caster, SkillCaster skillCaster, Skil case SkillTargetType.CursorPos: break; case SkillTargetType.Parent: + if (targetCaster.Type is SkillCastTargetType.Unit or SkillCastTargetType.Doodad) + { + target = targetCaster.ObjId > 0 ? WorldManager.Instance.GetBaseUnit(targetCaster.ObjId) : caster; + if (target != null) + { + targetCaster.ObjId = target.ObjId; + } + } break; case SkillTargetType.ChildSlave: break; @@ -541,6 +549,14 @@ private BaseUnit GetInitialTarget(BaseUnit caster, SkillCaster skillCaster, Skil case SkillTargetType.PetOwner: break; case SkillTargetType.IgnoreProtected: + if (targetCaster.Type is SkillCastTargetType.Unit or SkillCastTargetType.Doodad) + { + target = targetCaster.ObjId > 0 ? WorldManager.Instance.GetBaseUnit(targetCaster.ObjId) : caster; + if (target != null) + { + targetCaster.ObjId = target.ObjId; + } + } break; default: throw new NotSupportedException($"SkillTargetType not supported {Template.TargetType}"); @@ -591,13 +607,13 @@ public void Cast(BaseUnit caster, SkillCaster casterCaster, BaseUnit target, Ski { if (caster is not Unit unit) { return; } - var delay = 300; - // Will delay for 300 Milliseconds to eliminate the hanging of the skill - if (!caster.CheckInterval(delay)) - { - //Logger.Trace($"Skill: CooldownTime [{delay}]!"); - return; - } + //var delay = 300; + //// Will delay for 300 Milliseconds to eliminate the hanging of the skill + //if (!caster.CheckInterval(delay)) + //{ + // //Logger.Trace($"Skill: CooldownTime [{delay}]!"); + // return; + //} if (!_bypassGcd) { @@ -1047,7 +1063,7 @@ public void ApplyEffects(BaseUnit caster, SkillCaster casterCaster, BaseUnit tar } else { - var inventory = player.Inventory.CheckItems(SlotType.Inventory, lastAppliedEffect.ConsumeItemId, + var inventory = player.Inventory.CheckItems(SlotType.Bag, lastAppliedEffect.ConsumeItemId, lastAppliedEffect.ConsumeItemCount); var equipment = player.Inventory.CheckItems(SlotType.Equipment, lastAppliedEffect.ConsumeItemId, lastAppliedEffect.ConsumeItemCount); @@ -1219,8 +1235,8 @@ public void ApplyEffects(BaseUnit caster, SkillCaster casterCaster, BaseUnit tar // Doesn't matter, but by Template foreach (var (templateId, amount) in consumedItemTemplates) - player.Inventory.ConsumeItem(null, ItemTaskType.SkillEffectConsumption, templateId, - amount, null); + player.Inventory.ConsumeItem(null, ItemTaskType.SkillEffectGainItem, templateId, amount, null); + //player.Inventory.ConsumeItem(null, ItemTaskType.SkillEffectConsumption, templateId, amount, null); } } } diff --git a/AAEmu.Game/Models/Game/Skills/SkillCaster.cs b/AAEmu.Game/Models/Game/Skills/SkillCaster.cs index aaeade534a..bb5c997733 100644 --- a/AAEmu.Game/Models/Game/Skills/SkillCaster.cs +++ b/AAEmu.Game/Models/Game/Skills/SkillCaster.cs @@ -8,10 +8,10 @@ namespace AAEmu.Game.Models.Game.Skills; public enum SkillCasterType : byte { Unit = 0, - Unk1 = 1, // Doodad + Doodad = 1, // Doodad Item = 2, Mount = 3, // TODO mountSkillType - Doodad = 4 // Gimmick + Gimmick = 4 // Gimmick } public abstract class SkillCaster : PacketMarshaler @@ -26,7 +26,7 @@ public override void Read(PacketStream stream) public override PacketStream Write(PacketStream stream) { - stream.Write((byte)Type); + stream.Write((byte)Type); // skillCasterType stream.WriteBc(ObjId); return stream; } @@ -39,8 +39,8 @@ public static SkillCaster GetByType(SkillCasterType type) case SkillCasterType.Unit: obj = new SkillCasterUnit(); break; - case SkillCasterType.Unk1: - obj = new SkillCasterUnk1(); + case SkillCasterType.Doodad: + obj = new SkillCasterDoodad(); break; case SkillCasterType.Item: obj = new SkillItem(); @@ -48,8 +48,8 @@ public static SkillCaster GetByType(SkillCasterType type) case SkillCasterType.Mount: obj = new SkillCasterMount(); break; - case SkillCasterType.Doodad: - obj = new SkillDoodad(); + case SkillCasterType.Gimmick: + obj = new SkillCasterGimmik(); break; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); @@ -73,15 +73,15 @@ public SkillCasterUnit(uint objId) } } -public class SkillCasterUnk1 : SkillCaster +public class SkillCasterDoodad : SkillCaster { - public SkillCasterUnk1() + public SkillCasterDoodad() { } - public SkillCasterUnk1(uint objId) + public SkillCasterDoodad(uint objId) { - Type = SkillCasterType.Unk1; + Type = SkillCasterType.Doodad; ObjId = objId; } } @@ -170,15 +170,15 @@ public override PacketStream Write(PacketStream stream) } } -public class SkillDoodad : SkillCaster +public class SkillCasterGimmik : SkillCaster { - public SkillDoodad() + public SkillCasterGimmik() { } - public SkillDoodad(uint objId) + public SkillCasterGimmik(uint objId) { - Type = SkillCasterType.Doodad; + Type = SkillCasterType.Gimmick; ObjId = objId; } } diff --git a/AAEmu.Game/Models/Game/Skills/SkillConstants.cs b/AAEmu.Game/Models/Game/Skills/SkillConstants.cs index a60ba889f4..3f672d62cd 100644 --- a/AAEmu.Game/Models/Game/Skills/SkillConstants.cs +++ b/AAEmu.Game/Models/Game/Skills/SkillConstants.cs @@ -5,6 +5,7 @@ public enum SkillConstants : uint DecreaseMoveSpeed = 161, Shackle = 160, Snare = 27, + Dismount = 35837, PatronStatus = 8000001, Patron = 8000011, PatronPlus = 8000204, diff --git a/AAEmu.Game/Models/Game/Skills/SkillObject.cs b/AAEmu.Game/Models/Game/Skills/SkillObject.cs index dbb94535f6..f9c30db026 100644 --- a/AAEmu.Game/Models/Game/Skills/SkillObject.cs +++ b/AAEmu.Game/Models/Game/Skills/SkillObject.cs @@ -16,16 +16,24 @@ public enum SkillObjectType // added in 3+ Unk8 = 8, Unk9 = 9, - Unk10 = 0x0A, - Unk11 = 0x0B, - Unk12 = 0x0C, - Unk13 = 0x0D, - Unk14 = 0x0E, - Unk15 = 0x0F, - Unk16 = 0x10, - Unk17 = 0x11, - Unk18 = 0x12, - Unk19 = 0x13 + Unk10 = 10, + Unk11 = 11, + Unk12 = 12, + Unk13 = 13, + Unk14 = 14, + Unk15 = 15, + Unk16 = 16, + Unk17 = 17, + Unk18 = 18, + Unk19 = 19, + // added in 5+ + Unk20 = 20, + Unk21 = 21, + Unk22 = 22, + Unk23 = 23, + Unk24 = 24, + Unk25 = 25, + Unk26 = 26 } public class SkillObject : PacketMarshaler @@ -100,6 +108,28 @@ public static SkillObject GetByType(SkillObjectType flag) case SkillObjectType.Unk19: obj = new SkillObjectUnk19(); // added in 3.5.0.3 NA break; + case SkillObjectType.Unk20: + obj = new SkillObjectUnk20(); // added in 5+ + break; + case SkillObjectType.Unk21: + obj = new SkillObjectUnk21(); // added in 5+ + break; + case SkillObjectType.Unk22: + obj = new SkillObjectUnk22(); // added in 5+ + break; + case SkillObjectType.Unk23: + obj = new SkillObjectUnk23(); // added in 5+ + break; + case SkillObjectType.Unk24: + obj = new SkillObjectUnk24(); // added in 5+ + break; + case SkillObjectType.Unk25: + obj = new SkillObjectUnk25(); // added in 5+ + break; + case SkillObjectType.Unk26: + obj = new SkillObjectUnk26(); // added in 5+ + break; + case SkillObjectType.None: default: obj = new SkillObject(); break; @@ -262,7 +292,7 @@ public override PacketStream Write(PacketStream stream) // all bottom added in 3+ public class SkillObjectUnk8 : SkillObject { - public byte Type { get; set; } + public uint Type { get; set; } public float X { get; set; } public float Y { get; set; } public float Z { get; set; } @@ -270,7 +300,7 @@ public class SkillObjectUnk8 : SkillObject public override void Read(PacketStream stream) { - Type = stream.ReadByte(); + Type = stream.ReadUInt32(); X = Helpers.ConvertLongX(stream.ReadInt64()); Y = Helpers.ConvertLongX(stream.ReadInt64()); Z = stream.ReadSingle(); @@ -453,11 +483,11 @@ public override PacketStream Write(PacketStream stream) public class SkillObjectUnk16 : SkillObject { - public byte Package { get; set; } + public bool Package { get; set; } public override void Read(PacketStream stream) { - Package = stream.ReadByte(); + Package = stream.ReadBoolean(); } public override PacketStream Write(PacketStream stream) @@ -472,11 +502,11 @@ public override PacketStream Write(PacketStream stream) public class SkillObjectUnk17 : SkillObject { - public byte ByProc { get; set; } + public bool ByProc { get; set; } public override void Read(PacketStream stream) { - ByProc = stream.ReadByte(); + ByProc = stream.ReadBoolean(); } public override PacketStream Write(PacketStream stream) @@ -511,12 +541,12 @@ public override PacketStream Write(PacketStream stream) public class SkillObjectUnk19 : SkillObject { public bool AutoUseAAPoint { get; set; } - public int SmeltingDescId { get; set; } + public uint SmeltingDescId { get; set; } public override void Read(PacketStream stream) { AutoUseAAPoint = stream.ReadBoolean(); - SmeltingDescId = stream.ReadInt32(); + SmeltingDescId = stream.ReadUInt32(); } public override PacketStream Write(PacketStream stream) @@ -529,3 +559,127 @@ public override PacketStream Write(PacketStream stream) return stream; } } +public class SkillObjectUnk20 : SkillObject +{ + public uint CraftType { get; set; } + public int CraftCount { get; set; } + + public override void Read(PacketStream stream) + { + CraftType = stream.ReadUInt32(); + CraftCount = stream.ReadInt32(); + } + + public override PacketStream Write(PacketStream stream) + { + base.Write(stream); + stream.Write(CraftType); + stream.Write(CraftCount); + return stream; + } +} +public class SkillObjectUnk21 : SkillObject +{ + public byte EquipSlot { get; set; } + public uint Type { get; set; } + public bool AutoUseAAPoint { get; set; } + + public override void Read(PacketStream stream) + { + EquipSlot = stream.ReadByte(); + Type = stream.ReadUInt32(); + AutoUseAAPoint = stream.ReadBoolean(); + } + + public override PacketStream Write(PacketStream stream) + { + base.Write(stream); + stream.Write(EquipSlot); + stream.Write(Type); + stream.Write(AutoUseAAPoint); + return stream; + } +} +public class SkillObjectUnk22 : SkillObject +{ + public byte EquipSlot { get; set; } + public sbyte Level { get; set; } + + public override void Read(PacketStream stream) + { + EquipSlot = stream.ReadByte(); + Level = stream.ReadSByte(); + } + + public override PacketStream Write(PacketStream stream) + { + base.Write(stream); + stream.Write(EquipSlot); + stream.Write(Level); + return stream; + } +} +public class SkillObjectUnk23 : SkillObject +{ + public long Type { get; set; } + + public override void Read(PacketStream stream) + { + Type = stream.ReadInt64(); + } + + public override PacketStream Write(PacketStream stream) + { + base.Write(stream); + stream.Write(Type); + return stream; + } +} +public class SkillObjectUnk24 : SkillObject +{ + public byte PageIndex { get; set; } + + public override void Read(PacketStream stream) + { + PageIndex = stream.ReadByte(); + } + + public override PacketStream Write(PacketStream stream) + { + base.Write(stream); + stream.Write(PageIndex); + return stream; + } +} +public class SkillObjectUnk25 : SkillObject +{ + public uint MappingId { get; set; } + + public override void Read(PacketStream stream) + { + MappingId = stream.ReadUInt32(); + } + + public override PacketStream Write(PacketStream stream) + { + base.Write(stream); + stream.Write(MappingId); + return stream; + } +} +public class SkillObjectUnk26 : SkillObject +{ + public uint Color { get; set; } + + public override void Read(PacketStream stream) + { + Color = stream.ReadUInt32(); + } + + public override PacketStream Write(PacketStream stream) + { + base.Write(stream); + stream.Write(Color); + return stream; + } +} diff --git a/AAEmu.Game/Models/Game/Skills/Static/SkillResult.cs b/AAEmu.Game/Models/Game/Skills/Static/SkillResult.cs index f91d1daae2..76828b65ca 100644 --- a/AAEmu.Game/Models/Game/Skills/Static/SkillResult.cs +++ b/AAEmu.Game/Models/Game/Skills/Static/SkillResult.cs @@ -5,152 +5,179 @@ /// public enum SkillResult : byte { - Success = 0x0, - Failure = 0x1, - SourceDied = 0x2, - SourceAlive = 0x3, - TargetDied = 0x4, - TargetDestroyed = 0x5, - TargetAlive = 0x6, - OnCasting = 0x7, - CooldownTime = 0x8, - NoTarget = 0x9, - LackHealth = 0xA, - LackMana = 0xB, - Obstacle = 0xC, - OutofHeight = 0xD, - TooCloseRange = 0xE, - TooFarRange = 0xF, - OutofAngle = 0x10, - CannotCastInCombat = 0x11, - CannotCastWhileMoving = 0x12, - CannotCastInStun = 0x13, - CannotCastWhileWalking = 0x14, - CannotCastInSwimming = 0x15, - BlankMinded = 0x16, - Silence = 0x17, - Crippled = 0x18, - CannotCastInChanneling = 0x19, - CannotCastInPrison = 0x1A, - NeedStealth = 0x1B, - NeedNocombatTarget = 0x1C, - TargetImmune = 0x1D, - InvalidSkill = 0x1E, - InactiveAbility = 0x1F, - NotEnoughAbilityLevel = 0x20, - InvalidSource = 0x21, - InvalidTarget = 0x22, - InvalidLocation = 0x23, - NeedReagent = 0x24, - ItemLocked = 0x25, - NeedMoney = 0x26, - NeedLaborPower = 0x27, - SourceIsHanging = 0x28, - SourceIsRiding = 0x29, - HigherBuff = 0x2A, - NotPvpArea = 0x2B, - NotNow = 0x2C, - NoPerm = 0x2D, - BagFull = 0x2E, - ProtectedFaction = 0x2F, - ProtectedLevel = 0x30, - UnitReqsOrFail = 0x31, - SkillReqFail = 0x32, - BackpackOccupied = 0x33, - ObstacleForSpawnDoodad = 0x34, - CannotSpawnDoodadInHouse = 0x35, - CannotUseForSelf = 0x36, - NotPreoccupied = 0x37, - NotMyNpc = 0x38, - NotCheckedSecondPass = 0x39, - ZoneBanned = 0x3A, - InvalidGradeEnchantSupportItem = 0x3B, - CheckCharacterPStatMin = 0x3C, - CheckCharacterPStatMax = 0x3D, - ItemSecured = 0x3E, - InvalidAccountAttribute = 0x3F, - FestivalZone = 0x40, - AlreadyOtherPlayerBound = 0x41, - MateDead = 0x42, - CannotUnsummonUnderStunSleepRoot = 0x43, - LackHighAbilityResource = 0x44, - LackSourceItemSet = 0x45, - LackActability = 0x46, - UrkStart = 0x46, // Start offset for UnitReqsKindType -#pragma warning disable CA1069 // Enums values should not be duplicated - UrkLevel = 0x47, -#pragma warning restore CA1069 // Enums values should not be duplicated - UrkAbility = 0x48, - UrkRace = 0x49, - UrkGender = 0x4A, - UrkEquipSlot = 0x4B, - UrkEquipItem = 0x4C, - UrkOwnItem = 0x4D, - UrkTrainedSkill = 0x4E, - UrkCombat = 0x4F, - UrkStealth = 0x50, - UrkHealth = 0x51, - UrkBuff = 0x52, - UrkTargetBuff = 0x53, - UrkTargetCombat = 0x54, - UrkCanLearnCraft = 0x55, - UrkDoodadRange = 0x56, - UrkEquipShield = 0x57, - UrkNobuff = 0x58, - UrkTargetBuffTag = 0x59, - UrkCorpseRange = 0x5A, - UrkEquipWeaponType = 0x5B, - UrkTargetHealthLessThan = 0x5C, - UrkTargetNpc = 0x5D, - UrkTargetDoodad = 0x5E, - UrkEquipRanged = 0x5F, - UrkNoBuffTag = 0x60, - UrkCompleteQuestContext = 0x61, - UrkProgressQuestContext = 0x62, - UrkReadyQuestContext = 0x63, - UrkTargetNpcGroup = 0x64, - UrkAreaSphere = 0x65, - UrkExceptCompleteQuestContext = 0x66, - UrkPrecompleteQuestContext = 0x67, - UrkTargetOwnerType = 0x68, - UrkNotUnderWater = 0x69, - UrkFactionMatch = 0x6A, - UrkTod = 0x6B, - UrkMotherFaction = 0x6C, - UrkActabilityPoint = 0x6D, - UrkCrimePoint = 0x6E, - UrkHonorPoint = 0x6F, - UrkLivingPoint = 0x70, - UrkCrimeRecord = 0x71, - UrkJuryPoint = 0x72, - UrkSourceOwnerType = 0x73, - UrkAppellation = 0x74, - UrkInZone = 0x75, - UrkOutZone = 0x76, - UrkDominionOwner = 0x77, - UrkVerdictOnly = 0x78, - UrkFactionMatchOnly = 0x79, - UrkMotherFactionOnly = 0x7A, - UrkNationOwner = 0x7B, - UrkFactionMatchOnlyNot = 0x7C, - UrkMotherFactionOnlyNot = 0x7D, - UrkNationMember = 0x7E, - UrkNationMemberNot = 0x7F, - UrkNationOwnerAtPos = 0x80, - UrkDominionOwnerAtPos = 0x81, - UrkHousing = 0x82, - UrkHealthMargin = 0x83, - UrkManaMargin = 0x84, - UrkLaborPowerMargin = 0x85, - UrkNotOnMovingPhysicalVehicle = 0x86, - UrkMaxLevel = 0x87, - UrkExpeditionOwner = 0x88, - UrkExpeditionMember = 0x89, - UrkExceptProgressQuestContext = 0x8A, - UrkExceptReadyQuestContext = 0x8B, - UrkOwnItemNot = 0x8C, - UrkLessActabilityPoint = 0x8D, - UrkOwnQuestItemGroup = 0x8E, + // updated to version 5.0.7.0 + Success = 0, + Failure = 1, + SourceDied = 2, + SourceAlive = 3, + TargetDied = 4, + TargetDestroyed = 5, + TargetAlive = 6, + OnCasting = 7, + CooldownTime = 8, + NoTarget = 9, + LackHealth = 10, + LackMana = 11, + Obstacle = 12, + OutofHeight = 13, + TooCloseRange = 14, + TooFarRange = 15, + OutofAngle = 16, + CannotCastInCombat = 17, + CannotCastWhileMoving = 18, + CannotCastInStun = 19, + CannotCastWhileWalking = 20, + CannotCastInSwimming = 21, + BlankMinded = 22, + Silence = 23, + Crippled = 24, + CannotCastInChanneling = 25, + CannotCastInPrison = 26, + NeedStealth = 27, + NeedNocombatTarget = 28, + TargetImmune = 29, + InvalidSkill = 30, + InactiveAbility = 31, + NotEnoughAbilityLevel = 32, + InvalidSource = 33, + InvalidTarget = 34, + InvalidLocation = 35, + NeedReagent = 36, + ItemLocked = 37, + NeedMoney = 38, + NeedLaborPower = 39, + SourceIsHanging = 40, + SourceIsRiding = 41, + HigherBuff = 42, + NotPvpArea = 43, + NotNow = 44, + NoPerm = 45, + BagFull = 46, + ProtectedFaction = 47, + ProtectedLevel = 48, + UnitReqsOrFail = 49, + SkillReqFail = 50, + BackpackOccupied = 51, + ObstacleForSpawnDoodad = 52, + CannotSpawnDoodadInHouse = 53, + CannotUseForSelf = 54, + NotPreoccupied = 55, + NotMyNpc = 56, + NotCheckedSecondPass = 57, + ZoneBanned = 58, + InvalidGradeEnchantSupportItem = 59, + CheckCharacterPStatMin = 60, + CheckCharacterPStatMax = 61, + ItemSecured = 62, + InvalidAccountAttribute = 63, + FestivalZone = 64, + AlreadyOtherPlayerBound = 65, + CannotUnsummonUnderStunSleepRoot = 67, + LackHighAbilityResource = 68, + LackSourceItemSet = 69, + LackActability = 70, + OnlyDuringSwimming = 71, + UrkLevel = 72, // Start offset for UnitReqsKindType + UrkAbility = 73, + //UrkAbility = 164, + UrkRace = 74, + UrkGender = 75, + UrkEquipSlot = 76, + UrkEquipItem = 77, + UrkOwnItem = 78, + UrkTrainedSkill = 79, + UrkCombat = 80, + UrkStealth = 81, + UrkHealth = 82, + UrkBuff = 83, + UrkTargetBuff = 84, + UrkTargetCombat = 85, + UrkCanLearnCraft = 86, + UrkDoodadRange = 87, + UrkEquipShield = 88, + UrkNobuff = 89, + UrkTargetBuffTag = 90, + UrkCorpseRange = 91, + UrkEquipWeaponType = 92, + UrkTargetHealthLessThan = 93, + UrkTargetNpc = 94, + UrkTargetDoodad = 95, + UrkEquipRanged = 96, + UrkNoBuffTag = 97, + UrkCompleteQuestContext = 98, + UrkProgressQuestContext = 99, + UrkReadyQuestContext = 100, + UrkTargetNpcGroup = 101, + UrkAreaSphere = 102, + UrkExceptCompleteQuestContext = 103, + UrkPrecompleteQuestContext = 104, + UrkTargetOwnerType = 105, + UrkNotUnderWater = 106, + UrkFactionMatch = 107, + UrkTod = 108, + UrkMotherFaction = 109, + UrkActabilityPoint = 110, + UrkCrimePoint = 111, + UrkHonorPoint = 112, + UrkLivingPoint = 113, + UrkCrimeRecord = 114, + UrkJuryPoint = 115, + UrkSourceOwnerType = 116, + UrkAppellation = 117, + UrkInZone = 118, + UrkOutZone = 119, + UrkDominionOwner = 120, + UrkVerdictOnly = 121, + UrkFactionMatchOnly = 122, + UrkMotherFactionOnly = 123, + UrkNationOwner = 124, + UrkFactionMatchOnlyNot = 125, + UrkMotherFactionOnlyNot = 126, + UrkNationMember = 127, + UrkNationMemberNot = 128, + UrkNationOwnerAtPos = 129, + UrkDominionOwnerAtPos = 130, + UrkHousing = 131, + UrkHealthMargin = 132, + UrkManaMargin = 133, + UrkLaborPowerMargin = 134, + UrkMaxLevel = 136, + UrkExpeditionOwner = 137, + UrkExpeditionMember = 138, + UrkExceptProgressQuestContext = 139, + UrkExceptReadyQuestContext = 140, + UrkOwnItemNot = 141, + UrkLessActabilityPoint = 142, + UrkOwnQuestItemGroup = 143, + UrkLeadershipTotal = 144, + UrkLeadershipCurrent = 145, + UrkHero = 146, + UrkOwnItemCount = 149, + UrkHouse = 151, + UrkHouseOnly = 152, + UrkDecoLimitExpanded = 153, + UrkNotExpandable = 154, + UrkDoodadTargetFriendly = 155, + UrkDoodadTargetHostile = 156, + UrkDominionExpeditionMemberNot = 157, + UrkDominionMemberNot = 158, + UrkCannotUseBuildingHouse = 159, + UrkTargetNobuffTag = 160, + //UrkAbility = 164, + UrkTargetManaLessThan = 165, + UrkTargetManaMoreThan = 166, + UrkTargetHealthMoreThan = 167, + UrkBuffTag = 168, + UrkFamilyRole = 169, + UrkLaborPowerMarginLocal = 170, + UrkHeirLevel = 171, + UrkInZoneGroup = 172, + UrkUnderWater = 174, + UrkOwnAppellation = 175, + UrkEquipAppellation = 176, + UrkFullRechargedLaborPower = 178 +// default: +// result = "URK_UNKNOWN"; } // ReSharper disable InconsistentNaming @@ -159,8 +186,10 @@ public enum SkillResult : byte /// public enum SkillResultKeys { + // updated to version 5.0.7.0 // NOTE: do not edit the formatting or case of these enums ok, + skill_success, skill_failure, skill_source_died, skill_source_alive, @@ -210,20 +239,30 @@ public enum SkillResultKeys skill_protected_faction, skill_protected_level, skill_unit_reqs_or_fail, - backpack_occupied, + skill_skill_req_fail, + skill_backpack_occupied, skill_obstacle_for_spawn_doodad, skill_cannot_spawn_doodad_in_house, skill_cannot_use_for_self, skill_not_preoccupied, skill_not_my_npc, skill_not_checked_second_pass, - // SKILL_CANNOT_USE_HERE, + skill_zone_banned, // SKILL_CANNOT_USE_HERE skill_invalid_grade_enchant_support_item, skill_check_character_p_stat_min, skill_check_character_p_stat_max, + skill_item_secured, skill_invalid_account_attribute, + skill_festival_zone, + skill_already_other_player_bound, + skill_cannot_unsummon_under_stun_sleep_root, + skill_lack_high_ability_resource, + skill_lack_source_item_set, + skill_lack_actability, + skill_only_during_swimming, skill_urk_level, skill_urk_ability, + //skill_urk_ability, skill_urk_race, skill_urk_gender, skill_urk_equip_slot, @@ -253,6 +292,7 @@ public enum SkillResultKeys skill_urk_ready_quest_context, skill_urk_target_npc_group, skill_urk_area_sphere, + skill_urk_except_complete_quest_context, skill_urk_precomplete_quest_context, skill_urk_target_owner_type, skill_urk_not_under_water, @@ -260,38 +300,80 @@ public enum SkillResultKeys skill_urk_tod, skill_urk_mother_faction, skill_urk_actability_point, + skill_urk_crime_point, skill_urk_honor_point, skill_urk_living_point, + skill_urk_crime_record, + skill_urk_jury_point, + skill_urk_source_owner_type, + skill_urk_appellation, skill_urk_in_zone, skill_urk_out_zone, skill_urk_dominion_owner, skill_urk_verdict_only, skill_urk_faction_match_only, skill_urk_mother_faction_only, + skill_urk_nation_owner, skill_urk_faction_match_only_not, skill_urk_mother_faction_only_not, skill_urk_nation_member, skill_urk_nation_member_not, + skill_urk_nation_owner_at_pos, + skill_urk_dominion_owner_at_pos, skill_urk_housing, + skill_urk_health_margin, skill_urk_mana_margin, skill_urk_labor_power_margin, - skill_urk_unknown, skill_urk_max_level, -} -// ReSharper restore InconsistentNaming + skill_urk_expedition_owner, + skill_urk_expedition_member, + skill_urk_except_progress_quest_context, + skill_urk_except_ready_quest_context, + skill_urk_own_item_not, + skill_urk_less_actability_point, + skill_urk_own_quest_item_group, + skill_urk_leadership_total, + skill_urk_leadership_current, + skill_urk_hero, + skill_urk_own_item_count, + skill_urk_house, + skill_urk_house_only, + skill_urk_deco_limit_expanded, + skill_urk_not_expandable, + skill_urk_doodad_target_friendly, + skill_urk_doodad_target_hostile, + skill_urk_dominion_expedition_member_not, + skill_urk_dominion_member_not, + skill_urk_cannot_use_building_house, + skill_urk_target_nobuff_tag, + //skill_urk_ability = 164, + skill_urk_target_mana_less_than, + skill_urk_target_mana_more_than, + skill_urk_target_health_more_than, + skill_urk_buff_tag, + skill_urk_family_role, + skill_urk_labor_power_margin_local, + skill_urk_heir_level, + skill_urk_in_zone_group, + skill_urk_under_water, + skill_urk_own_appellation, + skill_urk_equip_appellation, + skill_urk_full_recharged_labor_power, + skill_urk_unknown +}// ReSharper restore InconsistentNaming /// /// Helper class to generate skill result error messages /// public static class SkillResultHelper { - public static SkillResult SkillResultErrorKeyToId(SkillResultKeys key) { // if (ClientVersion == r208022) - return SkillResultErrorKeyToIdFor_r208022(key.ToString()); + // if (ClientVersion == r500700) + return SkillResultErrorKeyToIdFor_r500700(key.ToString()); } - + /// /// Lookup the SkillResult for Version 1.2 r208022 /// @@ -303,138 +385,327 @@ private static SkillResult SkillResultErrorKeyToIdFor_r208022(string key) { case "": return SkillResult.Success; case "skill_success": return SkillResult.Success; - case "skill_failure": return (SkillResult)1; // Can't use this. - case "skill_source_died": return (SkillResult)2; // Can't be used while dead. - case "skill_source_alive": return (SkillResult)3; // Can only be used while dead. - case "skill_target_died": return (SkillResult)4; // Can't be used on a dead target. - case "skill_target_destroyed": return (SkillResult)5; // Target is already destroyed. - case "skill_target_alive": return (SkillResult)6; // Can't be used on a living target. - case "skill_on_casting": return (SkillResult)7; // Already performing an action. - case "skill_cooldown_time": return (SkillResult)8; // Can't be used right now. - case "skill_no_target": return (SkillResult)9; // Select a target. - case "skill_lack_health": return (SkillResult)10; // Insufficient health to use this. - case "skill_lack_mana": return (SkillResult)11; // Insufficient mana to use this. - case "skill_obstacle": return (SkillResult)12; // No line of sight. - case "skill_outof_height": return (SkillResult)13; // Target is on a different elevation. - case "skill_too_close_range": return (SkillResult)14; // Target is too close. - case "skill_too_far_range": return (SkillResult)15; // Target is too far. - case "skill_outof_angle": return (SkillResult)16; // Invalid target direction. - case "skill_cannot_cast_in_combat": return (SkillResult)17; // Can't be used in combat. - case "skill_cannot_cast_while_moving": return (SkillResult)18; // Can't be used while moving. - case "skill_cannot_cast_in_stun": return (SkillResult)19; // Can't be used while stunned. - case "skill_cannot_cast_while_walking": return (SkillResult)20; // Can't use while walking. - case "skill_cannot_cast_in_swimming": return (SkillResult)21; // Can't use this while swimming. - case "skill_blank_minded": return (SkillResult)22; // Can't use in ($1) unknown. - case "skill_silence": return (SkillResult)23; // Can't use magic skills while silenced. - case "skill_crippled": return (SkillResult)24; // Can't use physical skills while restrained. - case "skill_cannot_cast_in_channeling": return (SkillResult)25; // Can't use while busy. - case "skill_cannot_cast_in_prison": return (SkillResult)26; // Stay away from trouble while imprisoned. - case "skill_need_stealth": return (SkillResult)27; // Can only use while hidden. - case "skill_need_nocombat_target": return (SkillResult)28; // Target is in combat. - case "skill_target_immune": return (SkillResult)29; // Target is immune. - case "skill_invalid_skill": return (SkillResult)30; // Can't use this skill. - case "skill_inactive_ability": return (SkillResult)31; // Can't use this ability. - case "skill_not_enough_ability_level": return (SkillResult)32; // Insufficient skill level. - case "skill_invalid_source": return (SkillResult)33; // Can't be used in this state. - case "skill_invalid_target": return (SkillResult)34; // Invalid target. - case "skill_invalid_location": return (SkillResult)35; // Can't be used here. - case "skill_need_reagent": return (SkillResult)36; // Not enough ($1) unknown. - case "skill_item_locked": return (SkillResult)37; // Can't use this item. - case "skill_need_money": return (SkillResult)38; // Insufficient coins. - case "skill_need_labor_power": return (SkillResult)39; // Insufficient Labor Points. - case "skill_source_is_hanging": return (SkillResult)40; // Can't be used while airborne. - case "skill_source_is_riding": return (SkillResult)41; // Can't be used while riding. - case "skill_higher_buff": return (SkillResult)42; // Can't be used while a stronger effect is active. - case "skill_not_pvp_area": return (SkillResult)43; // PvP is not allowed in sanctuary zones. - case "skill_not_now": return (SkillResult)44; // Can't be used right now. - case "skill_no_perm": return (SkillResult)45; // You don't have permission. - case "skill_bag_full": return (SkillResult)46; // Your bag is full. - case "skill_protected_faction": return (SkillResult)47; // Can't instigate a raid against the ($1) unknown faction in this area. - case "skill_protected_level": return (SkillResult)48; // Can't start battles with characters Lv10 and below in protected zones. - case "skill_unit_reqs_or_fail": return (SkillResult)49; // Fails the requirements. + case "skill_failure": return (SkillResult)1; // Can't use this. + case "skill_source_died": return (SkillResult)2; // Can't be used while dead. + case "skill_source_alive": return (SkillResult)3; // Can only be used while dead. + case "skill_target_died": return (SkillResult)4; // Can't be used on a dead target. + case "skill_target_destroyed": return (SkillResult)5; // Target is already destroyed. + case "skill_target_alive": return (SkillResult)6; // Can't be used on a living target. + case "skill_on_casting": return (SkillResult)7; // Already performing an action. + case "skill_cooldown_time": return (SkillResult)8; // Can't be used right now. + case "skill_no_target": return (SkillResult)9; // Select a target. + case "skill_lack_health": return (SkillResult)10; // Insufficient health to use this. + case "skill_lack_mana": return (SkillResult)11; // Insufficient mana to use this. + case "skill_obstacle": return (SkillResult)12; // No line of sight. + case "skill_outof_height": return (SkillResult)13; // Target is on a different elevation. + case "skill_too_close_range": return (SkillResult)14; // Target is too close. + case "skill_too_far_range": return (SkillResult)15; // Target is too far. + case "skill_outof_angle": return (SkillResult)16; // Invalid target direction. + case "skill_cannot_cast_in_combat": return (SkillResult)17; // Can't be used in combat. + case "skill_cannot_cast_while_moving": return (SkillResult)18; // Can't be used while moving. + case "skill_cannot_cast_in_stun": return (SkillResult)19; // Can't be used while stunned. + case "skill_cannot_cast_while_walking": return (SkillResult)20; // Can't use while walking. + case "skill_cannot_cast_in_swimming": return (SkillResult)21; // Can't use this while swimming. + case "skill_blank_minded": return (SkillResult)22; // Can't use in ($1) unknown. + case "skill_silence": return (SkillResult)23; // Can't use magic skills while silenced. + case "skill_crippled": return (SkillResult)24; // Can't use physical skills while restrained. + case "skill_cannot_cast_in_channeling": return (SkillResult)25; // Can't use while busy. + case "skill_cannot_cast_in_prison": return (SkillResult)26; // Stay away from trouble while imprisoned. + case "skill_need_stealth": return (SkillResult)27; // Can only use while hidden. + case "skill_need_nocombat_target": return (SkillResult)28; // Target is in combat. + case "skill_target_immune": return (SkillResult)29; // Target is immune. + case "skill_invalid_skill": return (SkillResult)30; // Can't use this skill. + case "skill_inactive_ability": return (SkillResult)31; // Can't use this ability. + case "skill_not_enough_ability_level": return (SkillResult)32; // Insufficient skill level. + case "skill_invalid_source": return (SkillResult)33; // Can't be used in this state. + case "skill_invalid_target": return (SkillResult)34; // Invalid target. + case "skill_invalid_location": return (SkillResult)35; // Can't be used here. + case "skill_need_reagent": return (SkillResult)36; // Not enough ($1) unknown. + case "skill_item_locked": return (SkillResult)37; // Can't use this item. + case "skill_need_money": return (SkillResult)38; // Insufficient coins. + case "skill_need_labor_power": return (SkillResult)39; // Insufficient Labor Points. + case "skill_source_is_hanging": return (SkillResult)40; // Can't be used while airborne. + case "skill_source_is_riding": return (SkillResult)41; // Can't be used while riding. + case "skill_higher_buff": return (SkillResult)42; // Can't be used while a stronger effect is active. + case "skill_not_pvp_area": return (SkillResult)43; // PvP is not allowed in sanctuary zones. + case "skill_not_now": return (SkillResult)44; // Can't be used right now. + case "skill_no_perm": return (SkillResult)45; // You don't have permission. + case "skill_bag_full": return (SkillResult)46; // Your bag is full. + case "skill_protected_faction": return (SkillResult)47; // Can't instigate a raid against the ($1) unknown faction in this area. + case "skill_protected_level": return (SkillResult)48; // Can't start battles with characters Lv10 and below in protected zones. + case "skill_unit_reqs_or_fail": return (SkillResult)49; // Fails the requirements. // case "": return (SkillResult)50; // unknown - case "backpack_occupied": return (SkillResult)51; // Already carrying a pack. - case "skill_obstacle_for_spawn_doodad": return (SkillResult)52; // Blocked by an obstacle. - case "skill_cannot_spawn_doodad_in_house": return (SkillResult)53; // Can't place that here. - case "skill_cannot_use_for_self": return (SkillResult)54; // Can't use on yourself. - case "skill_not_preoccupied": return (SkillResult)55; // Can only be used on selected targets. - case "skill_not_my_npc": return (SkillResult)56; // You don't have permission. - case "skill_not_checked_second_pass": return (SkillResult)57; // Failed to pass the second password. - case "SKILL_CANNOT_USE_HERE": return (SkillResult)58; // Can't use this skill in this location. - case "skill_invalid_grade_enchant_support_item": return (SkillResult)59; // Can't use a Regrade Charm. - case "skill_check_character_p_stat_min": return (SkillResult)60; // You can downgrade this stat to ($1) unknown. - case "skill_check_character_p_stat_max": return (SkillResult)61; // You can upgrade this stat to ($1) unknown. - case "skill_item_secured": return (SkillResult)62; // 89 ?? skill_item_secured - case "skill_invalid_account_attribute": return (SkillResult)63; // Your account doesn't have the required permissions. - case "skill_urk_level": return (SkillResult)64; // Your level is too low. - case "skill_urk_ability": return (SkillResult)65; // Your stats are too low. - case "skill_urk_race": return (SkillResult)66; // Does not apply to this race. - case "skill_urk_gender": return (SkillResult)67; // Does not apply to this gender. - case "skill_urk_equip_slot": return (SkillResult)68; // Must be equipped with the proper gear. - case "skill_urk_equip_item": return (SkillResult)69; // Must be equipped with an item. - case "skill_urk_own_item": return (SkillResult)70; // You need ($1) unknown(|r.) - case "skill_urk_trained_skill": return (SkillResult)71; // You haven't learned this skill yet. - case "skill_urk_combat": return (SkillResult)72; // Can't be used in combat. - case "skill_urk_stealth": return (SkillResult)73; // Stealth status does not meet the requirements. - case "skill_urk_health": return (SkillResult)74; // Health does not meet the requirements. - case "skill_urk_buff": return (SkillResult)75; // Must be ($1) unknown. - case "skill_urk_target_buff": return (SkillResult)76; // Target must be ($1) unknown. - case "skill_urk_target_combat": return (SkillResult)77; // Target's combat status does not meet the requirements. - case "skill_urk_can_learn_craft": return (SkillResult)78; // You already learned this crafting skill. - case "skill_urk_doodad_range": return (SkillResult)79; // $1 is not in your immediate surroundings. - case "skill_urk_equip_shield": return (SkillResult)80; // Must be equipped with a shield. - case "skill_urk_nobuff": return (SkillResult)81; // Must not be under the effect of ($1) unknown. - case "skill_urk_target_buff_tag": return (SkillResult)82; // Target must be ($1) unknown. - case "skill_urk_corpse_range": return (SkillResult)83; // No corpses nearby. - case "skill_urk_equip_weapon_type": return (SkillResult)84; // Must be equipped with the correct weapon. - case "skill_urk_target_health_less_than": return (SkillResult)85; // Target's health must be low. - case "skill_urk_target_npc": return (SkillResult)86; // Can only be used on ($1) unknown. - case "skill_urk_target_doodad": return (SkillResult)87; // Invalid object. - case "skill_urk_equip_ranged": return (SkillResult)88; // Must be equipped with a ranged weapon. - case "skill_urk_no_buff_tag": return (SkillResult)89; // Can't do this now. - case "skill_urk_complete_quest_context": return (SkillResult)90; // Quest: $1 must be completed. - case "skill_urk_progress_quest_context": return (SkillResult)91; // Quest: $1 must be in-progress. - case "skill_urk_ready_quest_context": return (SkillResult)92; // Quest: $1 must be completed. - case "skill_urk_target_npc_group": return (SkillResult)93; // Invalid target. - case "skill_urk_area_sphere": return (SkillResult)94; // Can't be used here. - case "skill_urk_except_complete_quest_context": return (SkillResult)95; // 89 ?? Skill_urk_except_complete_quest_context - case "skill_urk_precomplete_quest_context": return (SkillResult)96; // Quest: $1 must be in-progress. - case "skill_urk_target_owner_type": return (SkillResult)97; // Invalid target. - case "skill_urk_not_under_water": return (SkillResult)98; // Can't use underwater. - case "skill_urk_faction_match": return (SkillResult)99; // You are not a member of the $1 faction. - case "skill_urk_tod": return (SkillResult)100; // Can't be used at this time. - case "skill_urk_mother_faction": return (SkillResult)101; // Your faction can't use this. - case "skill_urk_actability_point": return (SkillResult)102; // Insufficient $1 proficiency. - case "skill_urk_crime_point": return (SkillResult)103; // 89 ?? Skill_urk_crime_point - case "skill_urk_honor_point": return (SkillResult)104; // You don't meet the Honor Point requirements. - case "skill_urk_living_point": return (SkillResult)105; // You don't meet the Vocation Badge requirements. - case "skill_urk_crime_record": return (SkillResult)106; // 89 ?? Skill_urk_crime_record - case "skill_urk_jury_point": return (SkillResult)107; // 89 ?? Skill_urk_jury_point - case "skill_urk_source_owner_type": return (SkillResult)108; // 89 ?? Skill_urk_source_owner_type - case "skill_urk_appelation": return (SkillResult)109; // 89 ?? Skill_urk_appelation - case "skill_urk_in_zone": return (SkillResult)110; // Can only be used in $1. - case "skill_urk_out_zone": return (SkillResult)111; // Can't be used in $1. - case "skill_urk_dominion_owner": return (SkillResult)112; // Only Lords can do this. - case "skill_urk_verdict_only": return (SkillResult)113; // Your jury privileges have been revoked. You can no longer serve on juries. - case "skill_urk_faction_match_only": return (SkillResult)114; // You are not a member of the $1 faction. - case "skill_urk_mother_faction_only": return (SkillResult)115; // Your faction can't use this. - case "skill_urk_nation_owner": return (SkillResult)116; // 89 ?? Skill_urk_nation_owner - case "skill_urk_faction_match_only_not": return (SkillResult)117; // $1+ HP must be drained first. // This translation seems wrong - case "skill_urk_mother_faction_only_not": return (SkillResult)118; // The $1 sub faction can't do this. - case "skill_urk_nation_member": return (SkillResult)119; // You must be in a nation. - case "skill_urk_nation_member_not": return (SkillResult)120; // You can't be in a nation to do this. - case "skill_urk_nation_owner_at_pos": return (SkillResult)121; // 89 ?? Skill_urk_nation_owner_at_pos - case "skill_urk_dominion_owner_at_pos": return (SkillResult)122; // 89 ?? Skill_urk_dominion_owner_at_pos - case "skill_urk_housing": return (SkillResult)123; // You do not have $1. - case "skill_urk_health_margin": return (SkillResult)124; // 89 ?? Skill_urk_health_margin - case "skill_urk_mana_margin": return (SkillResult)125; // $1+ MP must be drained first. - case "skill_urk_labor_power_margin": return (SkillResult)126; // $1+ Labor must be drained first. - case "skill_urk_unknown": return (SkillResult)127; // Can't use this. - case "skill_urk_max_level": return (SkillResult)128; // Your level is too high. - case "skill_urk_expedition_owner": return (SkillResult)129; // 89 ?? Skill_urk_expedition_owner - case "skill_urk_expedition_member": return (SkillResult)130; // 89 ?? Skill_urk_expedition_member - // case "skill_urk_progress_quest_context": return (SkillResult)131; // 89 ?? Skill_urk_progress_quest_context - // case "skill_urk_ready_quest_context": return (SkillResult)132; // 89 ?? Skill_urk_ready_quest_context + case "backpack_occupied": return (SkillResult)51; // Already carrying a pack. + case "skill_obstacle_for_spawn_doodad": return (SkillResult)52; // Blocked by an obstacle. + case "skill_cannot_spawn_doodad_in_house": return (SkillResult)53; // Can't place that here. + case "skill_cannot_use_for_self": return (SkillResult)54; // Can't use on yourself. + case "skill_not_preoccupied": return (SkillResult)55; // Can only be used on selected targets. + case "skill_not_my_npc": return (SkillResult)56; // You don't have permission. + case "skill_not_checked_second_pass": return (SkillResult)57; // Failed to pass the second password. + case "SKILL_CANNOT_USE_HERE": return (SkillResult)58; // Can't use this skill in this location. + case "skill_invalid_grade_enchant_support_item": return (SkillResult)59; // Can't use a Regrade Charm. + case "skill_check_character_p_stat_min": return (SkillResult)60; // You can downgrade this stat to ($1) unknown. + case "skill_check_character_p_stat_max": return (SkillResult)61; // You can upgrade this stat to ($1) unknown. + case "skill_item_secured": return (SkillResult)62; // 89 ?? skill_item_secured + case "skill_invalid_account_attribute": return (SkillResult)63; // Your account doesn't have the required permissions. + case "skill_urk_level": return (SkillResult)64; // Your level is too low. + case "skill_urk_ability": return (SkillResult)65; // Your stats are too low. + case "skill_urk_race": return (SkillResult)66; // Does not apply to this race. + case "skill_urk_gender": return (SkillResult)67; // Does not apply to this gender. + case "skill_urk_equip_slot": return (SkillResult)68; // Must be equipped with the proper gear. + case "skill_urk_equip_item": return (SkillResult)69; // Must be equipped with an item. + case "skill_urk_own_item": return (SkillResult)70; // You need ($1) unknown(|r.) + case "skill_urk_trained_skill": return (SkillResult)71; // You haven't learned this skill yet. + case "skill_urk_combat": return (SkillResult)72; // Can't be used in combat. + case "skill_urk_stealth": return (SkillResult)73; // Stealth status does not meet the requirements. + case "skill_urk_health": return (SkillResult)74; // Health does not meet the requirements. + case "skill_urk_buff": return (SkillResult)75; // Must be ($1) unknown. + case "skill_urk_target_buff": return (SkillResult)76; // Target must be ($1) unknown. + case "skill_urk_target_combat": return (SkillResult)77; // Target's combat status does not meet the requirements. + case "skill_urk_can_learn_craft": return (SkillResult)78; // You already learned this crafting skill. + case "skill_urk_doodad_range": return (SkillResult)79; // $1 is not in your immediate surroundings. + case "skill_urk_equip_shield": return (SkillResult)80; // Must be equipped with a shield. + case "skill_urk_nobuff": return (SkillResult)81; // Must not be under the effect of ($1) unknown. + case "skill_urk_target_buff_tag": return (SkillResult)82; // Target must be ($1) unknown. + case "skill_urk_corpse_range": return (SkillResult)83; // No corpses nearby. + case "skill_urk_equip_weapon_type": return (SkillResult)84; // Must be equipped with the correct weapon. + case "skill_urk_target_health_less_than": return (SkillResult)85; // Target's health must be low. + case "skill_urk_target_npc": return (SkillResult)86; //Can only be used on ($1) unknown. + case "skill_urk_target_doodad": return (SkillResult)87; // Invalid object. + case "skill_urk_equip_ranged": return (SkillResult)88; // Must be equipped with a ranged weapon. + case "skill_urk_no_buff_tag": return (SkillResult)89; // Can't do this now. + case "skill_urk_complete_quest_context": return (SkillResult)90; // Quest: $1 must be completed. + case "skill_urk_progress_quest_context": return (SkillResult)91; // Quest: $1 must be in-progress. + case "skill_urk_ready_quest_context": return (SkillResult)92; // Quest: $1 must be completed. + case "skill_urk_target_npc_group": return (SkillResult)93; // Invalid target. + case "skill_urk_area_sphere": return (SkillResult)94; // Can't be used here. + case "skill_urk_except_complete_quest_context": return (SkillResult)95; // 89 ?? Skill_urk_except_complete_quest_context + case "skill_urk_precomplete_quest_context": return (SkillResult)96; // Quest: $1 must be in-progress. + case "skill_urk_target_owner_type": return (SkillResult)97; // Invalid target. + case "skill_urk_not_under_water": return (SkillResult)98; // Can't use underwater. + case "skill_urk_faction_match": return (SkillResult)99; // You are not a member of the $1 faction. + case "skill_urk_tod": return (SkillResult)100; // Can't be used at this time. + case "skill_urk_mother_faction": return (SkillResult)101; // Your faction can't use this. + case "skill_urk_actability_point": return (SkillResult)102; // Insufficient $1 proficiency. + case "skill_urk_crime_point": return (SkillResult)103; // 89 ?? Skill_urk_crime_point + case "skill_urk_honor_point": return (SkillResult)104; // You don't meet the Honor Point requirements. + case "skill_urk_living_point": return (SkillResult)105; // You don't meet the Vocation Badge requirements. + case "skill_urk_crime_record": return (SkillResult)106; // 89 ?? Skill_urk_crime_record + case "skill_urk_jury_point": return (SkillResult)107; // 89 ?? Skill_urk_jury_point + case "skill_urk_source_owner_type": return (SkillResult)108; // 89 ?? Skill_urk_source_owner_type + case "skill_urk_appelation": return (SkillResult)109; // 89 ?? Skill_urk_appelation + case "skill_urk_in_zone": return (SkillResult)110; // Can only be used in $1. + case "skill_urk_out_zone": return (SkillResult)111; // Can't be used in $1. + case "skill_urk_dominion_owner": return (SkillResult)112; // Only Lords can do this. + case "skill_urk_verdict_only": return (SkillResult)113; // Your jury privileges have been revoked. You can no longer serve on juries. + case "skill_urk_faction_match_only": return (SkillResult)114; // You are not a member of the $1 faction. + case "skill_urk_mother_faction_only": return (SkillResult)115; // Your faction can't use this. + case "skill_urk_nation_owner": return (SkillResult)116; // 89 ?? Skill_urk_nation_owner + case "skill_urk_faction_match_only_not": return (SkillResult)117; // $1+ HP must be drained first. // This translation seems wrong + case "skill_urk_mother_faction_only_not": return (SkillResult)118; // The $1 sub faction can't do this. + case "skill_urk_nation_member": return (SkillResult)119; // You must be in a nation. + case "skill_urk_nation_member_not": return (SkillResult)120; // You can't be in a nation to do this. + case "skill_urk_nation_owner_at_pos": return (SkillResult)121; // 89 ?? Skill_urk_nation_owner_at_pos + case "skill_urk_dominion_owner_at_pos": return (SkillResult)122; // 89 ?? Skill_urk_dominion_owner_at_pos + case "skill_urk_housing": return (SkillResult)123; // You do not have $1. + case "skill_urk_health_margin": return (SkillResult)124; // 89 ?? Skill_urk_health_margin + case "skill_urk_mana_margin": return (SkillResult)125; // $1+ MP must be drained first. + case "skill_urk_labor_power_margin": return (SkillResult)126; // $1+ Labor must be drained first. + case "skill_urk_unknown": return (SkillResult)127; // Can't use this. + case "skill_urk_max_level": return (SkillResult)128; // Your level is too high. + case "skill_urk_expedition_owner": return (SkillResult)129; // 89 ?? Skill_urk_expedition_owner + case "skill_urk_expedition_member": return (SkillResult)130; // 89 ?? Skill_urk_expedition_member + // case "skill_urk_progress_quest_context": return (SkillResult)131; // 89 ?? Skill_urk_progress_quest_context + // case "skill_urk_ready_quest_context": return (SkillResult)132; // 89 ?? Skill_urk_ready_quest_context + default: return SkillResult.Failure; + } + } + + private static SkillResult SkillResultErrorKeyToIdFor_r500700(string key) + { + switch (key) + { + // updated to version 5.0.7.0 + case "": return SkillResult.Success; + case "skill_success": return SkillResult.Success; + case "skill_failure": return (SkillResult)1; // Can't use this. + case "skill_source_died": return (SkillResult)2; // Can't be used while dead. + case "skill_source_alive": return (SkillResult)3; // Can only be used while dead. + case "skill_target_died": return (SkillResult)4; // Can't be used on a dead target. + case "skill_target_destroyed": return (SkillResult)5; // Target is already destroyed. + case "skill_target_alive": return (SkillResult)6; // Can't be used on a living target. + case "skill_on_casting": return (SkillResult)7; // Already performing an action. + case "skill_cooldown_time": return (SkillResult)8; // Can't be used right now. + case "skill_no_target": return (SkillResult)9; // Select a target. + case "skill_lack_health": return (SkillResult)10; // Insufficient health to use this. + case "skill_lack_mana": return (SkillResult)11; // Insufficient mana to use this. + case "skill_obstacle": return (SkillResult)12; // No line of sight. + case "skill_outof_height": return (SkillResult)13; // Target is on a different elevation. + case "skill_too_close_range": return (SkillResult)14; // Target is too close. + case "skill_too_far_range": return (SkillResult)15; // Target is too far. + case "skill_outof_angle": return (SkillResult)16; // Invalid target direction. + case "skill_cannot_cast_in_combat": return (SkillResult)17; // Can't be used in combat. + case "skill_cannot_cast_while_moving": return (SkillResult)18; // Can't be used while moving. + case "skill_cannot_cast_in_stun": return (SkillResult)19; // Can't be used while stunned. + case "skill_cannot_cast_while_walking": return (SkillResult)20; // Can't use while walking. + case "skill_cannot_cast_in_swimming": return (SkillResult)21; // Can't use this while swimming. + case "skill_blank_minded": return (SkillResult)22; // Can't use in $1 + case "skill_silence": return (SkillResult)23; // Can't use magic skills while silenced. + case "skill_crippled": return (SkillResult)24; // Can't use physical skills while restrained. + case "skill_cannot_cast_in_channeling": return (SkillResult)25; // Can't use while busy. + case "skill_cannot_cast_in_prison": return (SkillResult)26; // Stay away from trouble while imprisoned. + case "skill_need_stealth": return (SkillResult)27; // Can only use while hidden. + case "skill_need_nocombat_target": return (SkillResult)28; // Target is in combat. + case "skill_target_immune": return (SkillResult)29; // Target is immune. + case "skill_invalid_skill": return (SkillResult)30; // Can't use this skill. + case "skill_inactive_ability": return (SkillResult)31; // Can't use this ability. + case "skill_not_enough_ability_level": return (SkillResult)32; // Insufficient skill level. + case "skill_invalid_source": return (SkillResult)33; // Can't be used in this state. + case "skill_invalid_target": return (SkillResult)34; // Invalid target. + case "skill_invalid_location": return (SkillResult)35; // Can't be used here. + case "skill_need_reagent": return (SkillResult)36; // Not enough $1 + case "skill_item_locked": return (SkillResult)37; // Can't use this item. + case "skill_need_money": return (SkillResult)38; // Insufficient coins. + case "skill_need_labor_power": return (SkillResult)39; // Insufficient Labor Points. + case "skill_source_is_hanging": return (SkillResult)40; // Can't be used while airborne. + case "skill_source_is_riding": return (SkillResult)41; // Can't be used while riding. + case "skill_higher_buff": return (SkillResult)42; // Can't be used while a stronger effect is active. + case "skill_not_pvp_area": return (SkillResult)43; // PvP is not allowed in sanctuary zones. + case "skill_not_now": return (SkillResult)44; // Can't be used right now. + case "skill_no_perm": return (SkillResult)45; // You don't have permission. + case "skill_bag_full": return (SkillResult)46; // Your bag is full. + case "skill_protected_faction": return (SkillResult)47; // Can't instigate a raid against the $1 faction in this area. + case "skill_protected_level": return (SkillResult)48; // Can't start battles with characters Lv10 and below in protected zones. + case "skill_unit_reqs_or_fail": return (SkillResult)49; // Fails the requirements. + case "skill_skill_req_fail": return (SkillResult)50; // unknown + case "skill_backpack_occupied": return (SkillResult)51; // Already carrying a pack. + case "skill_obstacle_for_spawn_doodad": return (SkillResult)52; // Blocked by an obstacle. + case "skill_cannot_spawn_doodad_in_house": return (SkillResult)53; // Can't place that here. + case "skill_cannot_use_for_self": return (SkillResult)54; // Can't use on yourself. + case "skill_not_preoccupied": return (SkillResult)55; // Can only be used on selected targets. + case "skill_not_my_npc": return (SkillResult)56; // You don't have permission. + case "skill_not_checked_second_pass": return (SkillResult)57; // Failed to pass the second password. + case "SKILL_CANNOT_USE_HERE": return (SkillResult)58; // Can't use this skill in this location. + case "skill_invalid_grade_enchant_support_item": return (SkillResult)59; // Can't use a Regrade Charm. + case "skill_check_character_p_stat_min": return (SkillResult)60; // You can downgrade this stat to $1 + case "skill_check_character_p_stat_max": return (SkillResult)61; // You can upgrade this stat to $1 + case "skill_item_secured": return (SkillResult)62; // 89 ?? skill_item_secured + case "skill_invalid_account_attribute": return (SkillResult)63; // Your account doesn't have the required permissions. + case "skill_festival_zone": return (SkillResult)64; // Can't attack during a festival. + case "skill_already_other_player_bound": return (SkillResult)65; // Someone else is already using this. + //case "?": return (SkillResult)66; // + case "skill_cannot_unsummon_under_stun_sleep_root": return (SkillResult)67; // Can't be desummoned during certain debuff effects. + case "skill_lack_high_ability_resource": return (SkillResult)68; // Can't be desummoned during certain debuff effects. + case "skill_lack_source_item_set": return (SkillResult)69; // Not enough items. + case "skill_lack_actability": return (SkillResult)70; // Not enough proficiency. + case "skill_only_during_swimming": return (SkillResult)71; // Can be used only during swimming + case "skill_urk_level": return (SkillResult)72; // Your level is too low. + case "skill_urk_ability": return (SkillResult)73; // Your stats are too low. + case "skill_urk_race": return (SkillResult)74; // Does not apply to this race. + case "skill_urk_gender": return (SkillResult)75; // Does not apply to this gender. + case "skill_urk_equip_slot": return (SkillResult)76; // Must be equipped with the proper gear. + case "skill_urk_equip_item": return (SkillResult)77; // Must be equipped with an item. + case "skill_urk_own_item": return (SkillResult)78; // You need $1 + case "skill_urk_trained_skill": return (SkillResult)79; // You haven't learned this skill yet. + case "skill_urk_combat": return (SkillResult)80; // Can't be used in combat. + case "skill_urk_stealth": return (SkillResult)81; // Stealth status does not meet the requirements. + case "skill_urk_health": return (SkillResult)82; // Health does not meet the requirements. + case "skill_urk_buff": return (SkillResult)83; // Must be $1 + case "skill_urk_target_buff": return (SkillResult)84; // Target must be $1 + case "skill_urk_target_combat": return (SkillResult)85; // Target's combat status does not meet the requirements. + case "skill_urk_can_learn_craft": return (SkillResult)86; // You already learned this crafting skill. + case "skill_urk_doodad_range": return (SkillResult)87; // $1 are not in your immediate surroundings. + case "skill_urk_equip_shield": return (SkillResult)88; // Must be equipped with a shield. + case "skill_urk_nobuff": return (SkillResult)89; // Must not be under the effect of $1 + case "skill_urk_target_buff_tag": return (SkillResult)90; // Target must be $1 + case "skill_urk_corpse_range": return (SkillResult)91; // No corpses nearby. + case "skill_urk_equip_weapon_type": return (SkillResult)92; // Must be equipped with the correct weapon. + case "skill_urk_target_health_less_than": return (SkillResult)93; // Target's health must be low. + case "skill_urk_target_npc": return (SkillResult)94; // Can only be used on $1 + case "skill_urk_target_doodad": return (SkillResult)95; // Invalid object. + case "skill_urk_equip_ranged": return (SkillResult)96; // Must be equipped with a ranged weapon. + case "skill_urk_no_buff_tag": return (SkillResult)97; // Can't do this now. + case "skill_urk_complete_quest_context": return (SkillResult)98; // Quest: $1 must be completed. + case "skill_urk_progress_quest_context": return (SkillResult)99; // Quest: $1 must be in-progress. + case "skill_urk_ready_quest_context": return (SkillResult)100; // Quest: $1 must be completed. + case "skill_urk_target_npc_group": return (SkillResult)101; // Invalid target. + case "skill_urk_area_sphere": return (SkillResult)102; // Can't be used here. + case "skill_urk_except_complete_quest_context": return (SkillResult)103; // Must not have completed the quest '$1.' + case "skill_urk_precomplete_quest_context": return (SkillResult)104; // Quest: $1 must be in-progress. + case "skill_urk_target_owner_type": return (SkillResult)105; // Invalid target. + case "skill_urk_not_under_water": return (SkillResult)106; // Can't use underwater. + case "skill_urk_faction_match": return (SkillResult)107; // You are not a member of the $1 faction. + case "skill_urk_tod": return (SkillResult)108; // Can't be used at this time. + case "skill_urk_mother_faction": return (SkillResult)109; // Your faction can't use this. + case "skill_urk_actability_point": return (SkillResult)110; // Insufficient $1 proficiency. + case "skill_urk_crime_point": return (SkillResult)111; // 89 ?? Skill_urk_crime_point + case "skill_urk_honor_point": return (SkillResult)112; // Insufficient Honor. + case "skill_urk_living_point": return (SkillResult)113; // Insufficient Vocation Badges. + case "skill_urk_crime_record": return (SkillResult)114; // 89 ?? Skill_urk_crime_record + case "skill_urk_jury_point": return (SkillResult)115; // 89 ?? Skill_urk_jury_point + case "skill_urk_source_owner_type": return (SkillResult)116; // 89 ?? Skill_urk_source_owner_type + case "skill_urk_appelation": return (SkillResult)117; // 89 ?? Skill_urk_appelation + case "skill_urk_in_zone": return (SkillResult)118; // Can only be used in $1. + case "skill_urk_out_zone": return (SkillResult)119; // Can't be used in $1. + case "skill_urk_dominion_owner": return (SkillResult)120; // Only Lords can do this. + case "skill_urk_verdict_only": return (SkillResult)121; // Your jury privileges have been revoked. You can no longer serve on juries. + case "skill_urk_faction_match_only": return (SkillResult)122; // You are not a member of the $1 faction. + case "skill_urk_mother_faction_only": return (SkillResult)123; // Your faction can't use this. + case "skill_urk_nation_owner": return (SkillResult)124; // 89 ?? Skill_urk_nation_owner + case "skill_urk_faction_match_only_not": return (SkillResult)125; // The $1 faction can't use this. + case "skill_urk_mother_faction_only_not": return (SkillResult)126; // The $1 faction can't use this. + case "skill_urk_nation_member": return (SkillResult)127; // You must be in a nation. + case "skill_urk_nation_member_not": return (SkillResult)128; // You can't use this while in a nation. + case "skill_urk_nation_owner_at_pos": return (SkillResult)129; // 89 ?? Skill_urk_nation_owner_at_pos + case "skill_urk_dominion_owner_at_pos": return (SkillResult)130; // 89 ?? Skill_urk_dominion_owner_at_pos + case "skill_urk_housing": return (SkillResult)131; // You do not have $1. + case "skill_urk_health_margin": return (SkillResult)132; // $1+ HP must be drained first. + case "skill_urk_mana_margin": return (SkillResult)133; // $1+ MP must be drained first. + case "skill_urk_labor_power_margin": return (SkillResult)134; // $1+ Labor must be drained first. + //case "skill_urk_unknown": return (SkillResult)135; // Can't use this. NotOnMovingPhysicalVehicle + case "skill_urk_max_level": return (SkillResult)136; // Your level is too high. + case "skill_urk_expedition_owner": return (SkillResult)137; // 89 ?? Skill_urk_expedition_owner + case "skill_urk_expedition_member": return (SkillResult)138; // 89 ?? Skill_urk_expedition_member + case "skill_urk_except_progress_quest_context": return (SkillResult)139; // Quest: $1 must not be in-progress. + case "skill_urk_except_ready_quest_context": return (SkillResult)140; // Quest: $1 must not be in-progress. + case "skill_urk_own_item_not": return (SkillResult)141; // Can only carry one $1 at a time. + case "skill_urk_less_actability_point": return (SkillResult)142; // Can't be used, because your $1 proficiency is higher than $2. + case "skill_urk_own_quest_item_group": return (SkillResult)143; // Missing a required item. + case "skill_urk_leadership_total": return (SkillResult)144; // 89 ?? skill_urk_leadership_total + case "skill_urk_leadership_current": return (SkillResult)145; // 89 ?? skill_urk_leadership_current + case "skill_urk_hero": return (SkillResult)146; // 89 ?? skill_urk_hero + // Can't use this. + // Can't use this. + case "skill_urk_own_item_count": return (SkillResult)149; // Not enough $1. + // Can't use this. + case "skill_urk_house": return (SkillResult)151; // Wrong target. Choose a different building. + case "skill_urk_house_only": return (SkillResult)152; // Can only be used on buildings. + case "skill_urk_deco_limit_expanded": return (SkillResult)153; // Insufficient expansion tickets can't be used. + case "skill_urk_not_expandable": return (SkillResult)154; // Decor capacity can't be increased for this structure. + case "skill_urk_doodad_target_friendly": return (SkillResult)155; // Applies to friendly targets. + case "skill_urk_doodad_target_hostile": return (SkillResult)156; // Applies to hostile targets. + case "skill_urk_dominion_expedition_member_not": return (SkillResult)157; // Not available to members of a ruling guild. + case "skill_urk_dominion_member_not": return (SkillResult)158; // Your guild or nation must not own any territory. + case "skill_urk_cannot_use_building_house": return (SkillResult)159; // Can't be used on a building under construction. + case "skill_urk_target_nobuff_tag": return (SkillResult)160; // Can't be used on items under $1. + // Can't use this. + // Can't use this. + // Can't use this. + //case "skill_urk_ability": return (SkillResult)164; // Your stats are too low. + case "skill_urk_target_mana_less_than": return (SkillResult)165; // Target must have low mana. + case "skill_urk_target_mana_more_than": return (SkillResult)166; // Target must have high mana. + case "skill_urk_target_health_more_than": return (SkillResult)167; // Target must have high health. + case "skill_urk_buff_tag": return (SkillResult)168; // Must be $1. + case "skill_urk_family_role": return (SkillResult)169; // 89 ?? skill_urk_family_role + case "skill_urk_labor_power_margin_local": return (SkillResult)170; // $1+ Labor must be drained first. + case "skill_urk_heir_level": return (SkillResult)171; // Ancestral Level too low. + case "skill_urk_in_zone_group": return (SkillResult)172; // Can only be used in $1. + // Can't use this. + case "skill_urk_under_water": return (SkillResult)174; // Can only be used in the water. + case "skill_urk_own_appellation": return (SkillResult)175; // 89 ?? skill_urk_own_appellation + case "skill_urk_equip_appellation": return (SkillResult)176; // 89 ?? skill_urk_equip_appellation + // Can't use this. + case "skill_urk_full_recharged_labor_power": return (SkillResult)178; // Maximum amount of daily labor restored. default: return SkillResult.Failure; } } diff --git a/AAEmu.Game/Models/Game/Skills/Templates/BuffTemplate.cs b/AAEmu.Game/Models/Game/Skills/Templates/BuffTemplate.cs index aed0925074..0d750cc041 100644 --- a/AAEmu.Game/Models/Game/Skills/Templates/BuffTemplate.cs +++ b/AAEmu.Game/Models/Game/Skills/Templates/BuffTemplate.cs @@ -235,6 +235,11 @@ public void Start(BaseUnit caster, BaseUnit owner, Buff buff) RadarManager.Instance.RegisterForPublicTransport(character, TransferTelescopeRange); if (TelescopeRange > 0) RadarManager.Instance.RegisterForShips(character, TelescopeRange); + if (character.Buffs.CheckBuff((uint)BuffConstants.Dash)) + { + var template = new ManaRegenTemplate(character, buff.Template.Tick, buff.Template.TickLevelManaCost, character.Level); + ManaRegenManager.Instance.Register(character, template); + } } } diff --git a/AAEmu.Game/Models/Game/Units/Mate.cs b/AAEmu.Game/Models/Game/Units/Mate.cs index 92921eff2b..4144156388 100644 --- a/AAEmu.Game/Models/Game/Units/Mate.cs +++ b/AAEmu.Game/Models/Game/Units/Mate.cs @@ -504,7 +504,7 @@ public Mate() Tags = new List(); Charges = new List(); Passengers = new Dictionary(); - Equipment = new MateEquipmentContainer(0, SlotType.EquipmentMate, false, this); + Equipment = new MateEquipmentContainer(0, SlotType.PetRideEquipment, false, this); // TODO: Spawn this with the correct amount of seats depending on the template // 2 seats by default diff --git a/AAEmu.Game/Models/Game/Units/Slave.cs b/AAEmu.Game/Models/Game/Units/Slave.cs index 1a365f6a48..bb2231c41b 100644 --- a/AAEmu.Game/Models/Game/Units/Slave.cs +++ b/AAEmu.Game/Models/Game/Units/Slave.cs @@ -65,7 +65,7 @@ public class Slave : Unit public List Tags { get; set; } public List Charges { get; set; } public bool IsLoadedPlayerSlave { get; set; } - + public Slave() { AttachedDoodads = new List(); @@ -761,6 +761,31 @@ private void DestroyAttachedItems() } } + public Doodad GetDoodadByItemTemplateId(uint templateId) + { + foreach (var doodad in AttachedDoodads) + { + if (doodad.TemplateId == templateId) + { + return doodad; + } + } + + return null; + } + public Slave GetSlaveByItemTemplateId(uint templateId) + { + foreach (var slave in AttachedSlaves) + { + if (slave.TemplateId == templateId) + { + return slave; + } + } + + return null; + } + /// /// Creates the random debris created by destroying some of the vehicles (mostly ships) /// @@ -803,7 +828,7 @@ private void MarkSummoningItemAsDestroyed() item.RepairStartTime = DateTime.MinValue; item.SummonLocation = Vector3.Zero; item.IsDirty = true; - Summoner.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.MateDeath, new ItemUpdate(item), new List())); + Summoner.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.SlaveDeath, new ItemUpdate(item), new List())); } /// diff --git a/AAEmu.Game/Models/Game/Units/Static/UnitReqsKindType.cs b/AAEmu.Game/Models/Game/Units/Static/UnitReqsKindType.cs index 016a7b393e..e664813e99 100644 --- a/AAEmu.Game/Models/Game/Units/Static/UnitReqsKindType.cs +++ b/AAEmu.Game/Models/Game/Units/Static/UnitReqsKindType.cs @@ -1,107 +1,123 @@ namespace AAEmu.Game.Models.Game.Units.Static; +// updated to version 5.0.7.0 public enum UnitReqsKindType : uint { - // Name , KindId, // Value1 , Value2, additional info - None = 0x00, // Unused - Level = 0x01, // MinLevel, MaxLevel - Ability = 0x02, // AbilityType, Level - Race = 0x03, // RaceId - Gender = 0x04, // Gender (1 male, 2 female), unused + // Name, KindId, // Value1 , Value2, additional info + // --- Below is used in 1.2 --- + None = 0, // Unused + Level = 1, // MinLevel, MaxLevel + Ability = 2, // AbilityType, Level + Race = 3, // RaceId + Gender = 4, // Gender (1 male, 2 female), unused // 0x05 // 0x06 // 0x07 - EquipSlot = 0x08, // Slot, unused - EquipItem = 0x09, // ItemId, unused - OwnItem = 0x0A, // ItemId, unused - TrainedSkill = 0x0B, // SkillId?, unused?, there are no entries using this - Combat = 0x0C, // unused, unused, skill can only be used outside of combat - Stealth = 0x0D, // unused, unused, there are no entries for this? Must be in stealth mode maybe? - Health = 0x0E, // unused, unused, there are no entries using this - Buff = 0x0F, // BuffId, unused, must have buff active - TargetBuff = 0x10, // BuffId, unused, target must have buff - TargetCombat = 0x11, // unused, unused, target must not be in combat + EquipSlot = 8, // Slot, unused + EquipItem = 9, // ItemId, unused + OwnItem = 10, // ItemId, unused + TrainedSkill = 11, // SkillId?, unused?, there are no entries using this + Combat = 12, // unused, unused, skill can only be used outside of combat + Stealth = 13, // unused, unused, there are no entries for this? Must be in stealth mode maybe? + Health = 14, // unused, unused, there are no entries using this + Buff = 15, // BuffId, unused, must have buff active + TargetBuff = 16, // BuffId, unused, target must have buff + TargetCombat = 17, // unused, unused, target must not be in combat // 0x12 - CanLearnCraft = 0x13, // CraftId, unused, must not have learned craft - DoodadRange = 0x14, // DoodadId, range, range seems to be in millimeters - EquipShield = 0x15, // always 1, unused, have a shield equipped. 1 Might be the shield style? - NoBuff = 0x16, // BuffId, 0 or 1, must not have the buff, don't know what the 0 or 1 means - TargetBuffTag = 0x17, // Buff Tag, unused, Target must have buff tag - CorpseRange = 0x18, // range?, unused, there are no entries using this - EquipWeaponType = 0x19, // weapon type?, unused, there are no entries using this - TargetHealthLessThan = 0x1A, // MinHp% (always 1), MaxHp% - TargetNpc = 0x1B, // NpcId, unused, must target Npc - TargetDoodad = 0x1C, // DoodadId, unused, skill target must be a doodad - EquipRanged = 0x1D, // ranged weapon type, unused, ranged type: 0=Bow, 1=(any)Instrument - NoBuffTag = 0x1E, // Buff Tag, unused, must not have tag - CompleteQuestContext = 0x1F, // QuestId, unused, must have completed quest - ProgressQuestContext = 0x20, // QuestId, unused, quest must be in progress - ReadyQuestContext = 0x21, // QuestId, unused, quest must be in ready state - TargetNpcGroup = 0x22, // NpcGroupId, unknown, target must be from NpcGroup (don't know where to get those), unknown is 1 for one skill - AreaSphere = 0x23, // SphereId, where 0=OutSide 1=Inside? - ExceptCompleteQuestContext = 0x24, // QuestId, unused, most not have quest in completed state? - PreCompleteQuestContext = 0x25, // QuestId, unused, quest must be before it's completed state? - TargetOwnerType = 0x26, // OwnerType(BaseUnitType), unused - NotUnderWater = 0x27, // unused, unused, must not be under water - FactionMatch = 0x28, // FactionId, unused, must be of faction - Tod = 0x29, // TimeOfDay Start, TimeOfDay End, format is in-game hours x 100 (e.g. 1150 => 11h30) - MotherFaction = 0x2A, // FactionId, unused, mother faction must be - ActAbilityPoint = 0x2B, // ActAbilityId, Points, requires points amount of act ability to use - CrimePoint = 0x2C, // points min, points max - HonorPoint = 0x2D, // points min, points max - CrimeRecord = 0x2E, // min val, max val, val seems to be more of a standing rating that record count, 0=has crime point, 1= has no crime points, 9=??? - JuryPoint = 0x2F, // can be jury, unknown, value1 seems like a "can be jury" flag, not sure about the 2nd - SourceOwnerType = 0x30, // unused, unused, no idea how this is supposed to be owner type, all values are 0 and only used for AiEvents - Appellation = 0x31, // unused, unused, there are no entries using this - LivingPoint = 0x32, // unused, unused, there are no entries using this - InZone = 0x33, // Zone ID, unused, Must be inside Zone ID - OutZone = 0x34, // Zone ID, unused, Must be outside Zone ID (unused) - DominionOwner = 0x35, // unused, unused, looks like this is meant for castle area rulers - VerdictOnly = 0x36, // unused, unused, target must be suspect (used to catch bots) - FactionMatchOnly = 0x37, // FactionId, unused, must be of faction (used for pirates 161) - MotherFactionOnly = 0x38, // FactionId, unused, must be of given mother faction - NationOwner = 0x39, // unused, unused, must be nation monarch - FactionMatchOnlyNot = 0x3A, // FactionId, unused, must NOT be of faction - MotherFactionOnlyNot = 0x3B, // FactionId, unused, must NOT be of given mother faction - NationMember = 0x3C, // unused, unused, must be member of a player nation - NationMemberNot = 0x3D, // unused, unused, must NOT be member of a player nation (unused) - NationOwnerAtPos = 0x3E, // unused, unused, player nation owner needs to be in their owning zone - DominionOwnerAtPos = 0x3F, // unused, unused, castle owner needs to be in their owning zone - Housing = 0x40, // unused, unused, housing area id, housing type owned maybe? unused as it reference a non-existing quest - HealthMargin = 0x41, // Health Margin, unused, margin <= max - current, there are no entries using this - ManaMargin = 0x42, // Mana Margin, unused, margin <= max - current, there are no entries using this - LaborPowerMargin = 0x43, // Labor Margin, unused, minimum amount of labor below cap (margin <= max - current) - NotOnMovingPhysicalVehicle = 0x44, // unused, unused, must not be driving/sitting on a moving vehicle - MaxLevel = 0x45, // MaxLevel, unused, maximum allowed level to use - ExpeditionOwner = 0x46, // unused, unused, must be guild owner, unused - ExpeditionMember = 0x47, // unused, unused, must be guild member, unused - ExceptProgressQuestContext = 0x48, // QuestId, unused, must not have started quest, used for mutually exclusive quests - ExceptReadyQuestContext = 0x49, // QuestId, unused, must not have finished quest, used for mutually exclusive quests - // --- Below is not used in 1.2 --- - OwnItemNot = 0x4A, // ItemId, unused, must NOT own item, unused - LessActAbilityPoint = 0x4B, // ActAbility, Points, unused - OwnQuestItemGroup = 0x4C, // unused, unused, there are no entries using this - LeadershipTotal = 0x4D, // unused, unused, there are no entries using this - LeadershipCurrent = 0x4E, // unused, unused, there are no entries using this - Hero = 0x4F, // unused, unused, there are no entries using this - DominionExpeditionMember = 0x50, // unused, unused, there are no entries using this - DominionNationMember = 0x51, // unused, unused, there are no entries using this - OwnItemCount = 0x52, // unused, unused, there are no entries using this - House = 0x53, // unused, unused, there are no entries using this - DoodadTargetFriendly = 0x54, // unused, unused, there are no entries using this - DoodadTargetHostile = 0x55, // unused, unused, there are no entries using this - DominionExpeditionMemberNot = 0x56, // unused, unused, there are no entries using this - DominionMemberNot = 0x57, // unused, unused, there are no entries using this - InZoneGroupHousingExist = 0x58, // unused, unused, there are no entries using this - TargetNoBuffTag = 0x59, // unused, unused, there are no entries using this - ExpeditionLevel = 0x5A, // unused, unused, there are no entries using this - IsResident = 0x5B, // unused, unused, there are no entries using this - ResidentServicePoint = 0x5C, // unused, unused, there are no entries using this - HighAbilityLevel = 0x5D, // unused, unused, there are no entries using this - FamilyRole = 0x5E, // unused, unused, there are no entries using this - TargetManaLessThan = 0x5F, // unused, unused, there are no entries using this - TargetManaMoreThan = 0x60, // unused, unused, there are no entries using this - TargetHealthMoreThan = 0x61, // unused, unused, there are no entries using this - BuffTag = 0x62, // unused, unused, there are no entries using this - LaborPowerMarginLocal = 0x63, // unused, unused, there are no entries using this + CanLearnCraft = 19, // CraftId, unused, must not have learned craft + DoodadRange = 20, // DoodadId, range, range seems to be in millimeters + EquipShield = 21, // always 1, unused, have a shield equipped. 1 Might be the shield style? + NoBuff = 22, // BuffId, 0 or 1, must not have the buff, don't know what the 0 or 1 means + TargetBuffTag = 23, // Buff Tag, unused, Target must have buff tag + CorpseRange = 24, // range?, unused, there are no entries using this + EquipWeaponType = 25, // weapon type?, unused, there are no entries using this + TargetHealthLessThan = 26, // MinHp% (always 1), MaxHp% + TargetNpc = 27, // NpcId, unused, must target Npc + TargetDoodad = 28, // DoodadId, unused, skill target must be a doodad + EquipRanged = 29, // ranged weapon type, unused, ranged type: 0=Bow, 1=(any)Instrument + NoBuffTag = 30, // Buff Tag, unused, must not have tag + CompleteQuestContext = 31, // Quest Component Id, unused, must have completed quest + ProgressQuestContext = 32, // Quest Component Id, unused, quest must be in progress + ReadyQuestContext = 33, // Quest Component Id, unused, quest must be in ready state + TargetNpcGroup = 34, // NpcGroupId, unknown, target must be from NpcGroup (don't know where to get those), unknown is 1 for one skill + AreaSphere = 35, // SphereId, where 0=OutSide 1=Inside? + ExceptCompleteQuestContext = 36, // Quest Component Id, unused, most not have quest in completed state? + PreCompleteQuestContext = 37, // Quest Component Id, unused, quest must be before it's completed state? + TargetOwnerType = 38, // OwnerType(BaseUnitType), unused + NotUnderWater = 39, // unused, unused, must not be under water + FactionMatch = 40, // FactionId, unused, must be of faction + Tod = 41, // TimeOfDay Start, TimeOfDay End, format is in-game hours x 100 (e.g. 1150 => 11h30) + MotherFaction = 42, // FactionId, unused, mother faction must be + ActAbilityPoint = 43, // ActAbilityId, Points, requires points amount of act ability to use + CrimePoint = 44, // points min, points max + HonorPoint = 45, // points min, points max + LivingPoint = 50, // unused, unused, there are no entries using this + CrimeRecord = 46, // min val, max val, val seems to be more of a standing rating that record count, 0=has crime point, 1= has no crime points, 9=??? + JuryPoint = 47, // can be jury, unknown, value1 seems like a "can be jury" flag, not sure about the 2nd + SourceOwnerType = 48, // unused, unused, no idea how this is supposed to be owner type, all values are 0 and only used for AiEvents + Appellation = 49, // unused, unused, there are no entries using this + InZone = 51, // Zone ID, unused, Must be inside Zone ID + OutZone = 52, // Zone ID, unused, Must be outside Zone ID (unused) + DominionOwner = 53, // unused, unused, looks like this is meant for castle area rulers + VerdictOnly = 54, // unused, unused, target must be suspect (used to catch bots) + FactionMatchOnly = 55, // FactionId, unused, must be of faction (used for pirates 161) + MotherFactionOnly = 56, // FactionId, unused, must be of given mother faction + NationOwner = 57, // unused, unused, must be nation monarch + FactionMatchOnlyNot = 58, // FactionId, unused, must NOT be of faction + MotherFactionOnlyNot = 59, // FactionId, unused, must NOT be of given mother faction + NationMember = 60, // unused, unused, must be member of a player nation + NationMemberNot = 61, // unused, unused, must NOT be member of a player nation (unused) + NationOwnerAtPos = 62, // unused, unused, player nation owner needs to be in their owning zone + DominionOwnerAtPos = 63, // unused, unused, castle owner needs to be in their owning zone + Housing = 64, // unused, unused, housing area id, housing type owned maybe? unused as it reference a non-existing quest + HealthMargin = 65, // Health Margin, unused, margin <= max - current, there are no entries using this + ManaMargin = 66, // Mana Margin, unused, margin <= max - current, there are no entries using this + LaborPowerMargin = 67, // Labor Margin, unused, minimum amount of labor below cap (margin <= max - current) + NotOnMovingPhysicalVehicle = 68, // unused, unused, must not be driving/sitting on a moving vehicle + MaxLevel = 69, // MaxLevel, unused, maximum allowed level to use + ExpeditionOwner = 70, // unused, unused, must be guild owner, unused + ExpeditionMember = 71, // unused, unused, must be guild member, unused + ExceptProgressQuestContext = 72, // Quest Component Id, unused, must not have started quest, used for mutually exclusive quests + ExceptReadyQuestContext = 73, // Quest Component Id, unused, must not have finished quest, used for mutually exclusive quests + // --- Below is used in 3.0 --- + OwnItemNot = 74, // ItemId, unused, must NOT own item, unused + LessActAbilityPoint = 75, // ActAbility, Points, unused + OwnQuestItemGroup = 76, // unused, unused, there are no entries using this + LeadershipTotal = 77, // unused, unused, there are no entries using this + LeadershipCurrent = 78, // unused, unused, there are no entries using this + Hero = 79, // unused, unused, there are no entries using this + DominionExpeditionMember = 80, // unused, unused, there are no entries using this + DominionNationMember = 81, // unused, unused, there are no entries using this + OwnItemCount = 82, // unused, unused, there are no entries using this + House = 83, // unused, unused, there are no entries using this + //HouseOnly = 100, // unused, unused, there are no entries using this + //DecoLimitExpanded = 101, // unused, unused, there are no entries using this + //NotExpandable = 102, // unused, unused, there are no entries using this + DoodadTargetFriendly = 84, // unused, unused, there are no entries using this + DoodadTargetHostile = 85, // unused, unused, there are no entries using this + DominionExpeditionMemberNot = 86, // unused, unused, there are no entries using this + DominionMemberNot = 87, // unused, unused, there are no entries using this + InZoneGroupHousingExist = 88, // unused, unused, there are no entries using this + CannotUseBuildingHouse = 101, // unused, unused, there are no entries using this + TargetNoBuffTag = 89, // unused, unused, there are no entries using this + ExpeditionLevel = 90, // unused, unused, there are no entries using this + IsResident = 91, // unused, unused, there are no entries using this + ResidentServicePoint = 92, // unused, unused, there are no entries using this + HighAbilityLevel = 93, // unused, unused, there are no entries using this + FamilyRole = 94, // unused, unused, there are no entries using this + TargetManaLessThan = 95, // unused, unused, there are no entries using this + TargetManaMoreThan = 96, // unused, unused, there are no entries using this + TargetHealthMoreThan = 97, // unused, unused, there are no entries using this + BuffTag = 98, // unused, unused, there are no entries using this + // --- Below is used in 5.0 --- + LaborPowerMarginLocal = 99, // unused, unused, there are no entries using this + HouseOnly = 100, // unused, unused, there are no entries using this + DecoLimitExpanded = 101, // unused, unused, there are no entries using this + NotExpandable = 102, // unused, unused, there are no entries using this + HeirLevel = 104, // unused, unused, there are no entries using this + InZoneGroup = 105, // unused, unused, there are no entries using this + UnderWater = 106, // unused, unused, there are no entries using this + OwnAppellation = 107, // unused, unused, there are no entries using this + EquipAppellation = 115, // unused, unused, there are no entries using this + FullRechargedLaborPower = 9000000 // unused, unused, there are no entries using this } diff --git a/AAEmu.Game/Models/Game/Units/UnitAttribute.cs b/AAEmu.Game/Models/Game/Units/UnitAttribute.cs index 5fe6fb8872..691b2974a3 100644 --- a/AAEmu.Game/Models/Game/Units/UnitAttribute.cs +++ b/AAEmu.Game/Models/Game/Units/UnitAttribute.cs @@ -2,171 +2,191 @@ public enum UnitAttribute : byte { - Str = 0, - Dex = 1, - Sta = 2, - Int = 3, - Spi = 4, - Fai = 5, - MaxHealth = 6, - MaxMana = 7, - Armor = 8, - MoveSpeedMul = 10, - HealthRegen = 11, - ManaRegen = 12, - Facets = 13, - MeleeCritical = 16, - MeleeCriticalBonus = 17, - MeleeAntiMiss = 18, - MeleeDodge = 20, - MeleeBlock = 21, - MeleeParry = 22, - RangedAntiMiss = 23, - RangedCritical = 25, - RangedCriticalBonus = 26, - SpellAntiMiss = 28, - SpellCritical = 30, - SpellCriticalBonus = 31, - MeleeDpsInc = 33, - RangedDpsInc = 34, - SpellDpsInc = 35, - MainhandSpeed = 36, - MainhandDamageMin = 37, - MainhandDamageMax = 38, - OffhandSpeed = 41, - OffhandDamageMin = 42, - OffhandDamageMax = 43, - RangedSpeed = 46, - RangedDamageMin = 47, - RangedDamageMax = 48, - MeleeDamageMul = 51, - RangedDamageMul = 52, - SpellDamageMul = 53, - MeleeSpeedMul = 54, - RangedSpeedMul = 55, - IncomingHealMul = 56, - IgnoreArmor = 57, - IncomingDamageMul = 58, - RangedDodge = 59, - RangedBlock = 60, - AggroRangeMul = 61, - IncomingAggroMul = 62, - Hovering = 63, - MagicResist = 64, - MagicStability = 65, - SwimSpeedMul = 66, - PersistentHealthRegen = 67, - PersistentManaRegen = 68, - ArmorType = 69, - ArmorTypeCoverage = 70, - CastingTimeMul = 71, - TurnSpeed = 72, - GravityMul = 73, - GlobalCooldownMul = 74, - TwohandSpeedMul = 75, - MeleeCriticalMul = 77, - MeleeAntiMissMul = 78, - MeleeDodgeMul = 79, - MeleeBlockMul = 80, - MeleeParryMul = 81, - RangedCriticalMul = 82, - RangedAntiMissMul = 83, - RangedDodgeMul = 84, - RangedBlockMul = 85, - SpellCriticalMul = 86, - SpellDps = 87, - SpellAntiMissMul = 88, - CastingTolerance = 89, - AggroMul = 90, - LungCapacity = 91, - FallDamageMul = 92, - LadderSpeedMul = 93, - DetectStealthRangeMul = 94, - ExpMul = 95, - MainhandDps = 96, - OffhandDps = 97, - RangedDps = 98, - ActabilityArchemy = 99, - ActabilityArchitecture = 100, - ActabilityCook = 101, - ActabilityHandicraft = 102, - ActabilityLivestock = 103, - ActabilityFarm = 104, - ActabilityFish = 105, - ActabilityLumber = 106, - ActabilityCollection = 107, - ActabilityMachinery = 108, - ActabilityMetal = 109, - ActabilityPrint = 110, - ActabilityMine = 111, - ActabilityStonemason = 112, - ActabilitySewing = 113, - ActabilitySkin = 114, - ActabilityWeapon = 115, - ActabilityCarpentry = 116, - ActabilityTheft = 117, - ActabilityBusiness = 118, - AttackAnimSpeedMul = 119, - HealMul = 120, - BackattackMeleeDamageMul = 121, - BackattackRangedDamageMul = 122, - BackattackSpellDamageMul = 123, - FrictionMul = 124, - HonorPointLoseMul = 125, - HonorPointGainBattleField = 126, - HonorPointGainBattleFieldMul = 127, - HonorPointGainNpcKill = 128, - HonorPointGainNpcKillMul = 129, - HonorPointGainTrial = 130, - HonorPointGainTrialMul = 131, - HonorPointGainWar = 132, - HonorPointGainWarMul = 133, - HonorPointGainQuest = 134, - HonorPointGainQuestMul = 135, - LivingPointGain = 136, - LivingPointGainMul = 137, - ActabilityComposition = 138, - UnderwaterSwimSpeedMul = 139, - DropRateMul = 140, - LootGoldMul = 141, - IncomingMeleeDamageAdd = 142, - IncomingMeleeDamageMul = 143, - IncomingRangedDamageAdd = 144, - IncomingRangedDamageMul = 145, - IncomingSpellDamageAdd = 146, - IncomingSpellDamageMul = 147, - IncomingSiegeDamageAdd = 148, - IncomingSiegeDamageMul = 149, - SpellDamageCritical = 150, - SpellDamageCriticalMul = 151, - SpellDamageCriticalBonus = 152, - RangedParry = 153, - RangedParryMul = 154, - //Fill in when we need? - /* - DEATH_DURABILITY_LOSS_RATIO_MUL = 0x9B, - PENALTY_EXP_MUL = 0x9C, - RECOVERABLE_EXP_MUL = 0x9D, - ACTABILITY_LANG_NUIAN = 0x9E, - ACTABILITY_LANG_ELF = 0x9F, - ACTABILITY_LANG_HARIHARAN = 0xA0, - ACTABILITY_LANG_FERRE = 0xA1, - ACTABILITY_LANG_WESTCOMMON = 0xA2, - ACTABILITY_LANG_EASTCOMMON = 0xA3, - ACTABILITY_LANG_DWARF = 0xA4, - ACTABILITY_LANG_WARBORN = 0xA5,*/ - HealDps = 173, - HealCritical = 174, - HealDpsInc = 175, - HealCriticalBonus = 176, - Block = 177, - Dodge = 178, - BlockMul = 179, - DodgeMul = 180, - BullsEye = 181, - BattleResist = 182, - Flexibility = 183, - MagicPenetration = 184, - HealCriticalMul = 185, - ExpByLaborPowerMul = 186, + // updated to version 5.0.7.0 + Str = 0, // str + Dex = 1, // dex + Sta = 2, // sta + Int = 3, // int + Spi = 4, // spi + Fai = 5, // fai + MaxHealth = 6, // max_health + MaxMana = 7, // max_mana + Armor = 8, // armor + MoveSpeedMul = 10, // move_speed_mul + HealthRegen = 11, // health_regen + ManaRegen = 12, // mana_regen + Facets = 13, // facets + MeleeCritical = 16, // melee_critical + MeleeCriticalBonus = 17, // melee_critical_bonus + MeleeAntiMiss = 18, // melee_anti_miss + MeleeParry = 22, // melee_parry + RangedAntiMiss = 23, // ranged_anti_miss + RangedCritical = 25, // ranged_critical + RangedCriticalBonus = 26, // ranged_critical_bonus + SpellAntiMiss = 28, // spell_anti_miss + SpellCritical = 30, // spell_critical + SpellCriticalBonus = 31, // spell_critical_bonus + MeleeDpsInc = 33, // melee_dps_inc + RangedDpsInc = 34, // ranged_dps_inc + SpellDpsInc = 35, // spell_dps_inc + MainhandSpeed = 36, // mainhand_speed + MainhandDamageMin = 37, // mainhand_damage_min + MainhandDamageMax = 38, // mainhand_damage_max + OffhandSpeed = 41, // offhand_speed + OffhandDamageMin = 42, // offhand_damage_min + OffhandDamageMax = 43, // offhand_damage_max + RangedSpeed = 46, // ranged_speed + RangedDamageMin = 47, // ranged_damage_min + RangedDamageMax = 48, // ranged_damage_max + MeleeDamageMul = 51, // melee_damage_mul + RangedDamageMul = 52, // ranged_damage_mul + SpellDamageMul = 53, // spell_damage_mul + MeleeSpeedMul = 54, // melee_speed_mul + RangedSpeedMul = 55, // ranged_speed_mul + IncomingHealMul = 56, // incoming_heal_mul + IgnoreArmor = 57, // ignore_armor + IncomingDamageMul = 58, // incoming_damage_mul + AggroRangeMul = 61, // aggro_range_mul + IncomingAggroMul = 62, // incoming_aggro_mul + Hovering = 63, // hovering + MagicResist = 64, // magic_resist + SwimSpeedMul = 66, // swim_speed_mul + PersistentHealthRegen = 67, // persistent_health_regen + PersistentManaRegen = 68, // persistent_mana_regen + ArmorType = 69, // armor_type + ArmorTypeCoverage = 70, // armor_type_coverage + CastingTimeMul = 71, // casting_time_mul + TurnSpeed = 72, // turn_speed + GravityMul = 73, // gravity_mul + GlobalCooldownMul = 74, // global_cooldown_mul + TwohandSpeedMul = 75, // twohand_speed_mul + MeleeCriticalMul = 77, // melee_critical_mul + MeleeAntiMissMul = 78, // melee_anti_miss_mul + MeleeParryMul = 81, // melee_parry_mul + RangedCriticalMul = 82, // ranged_critical_mul + RangedAntiMissMul = 83, // ranged_anti_miss_mul + SpellCriticalMul = 86, // spell_critical_mul + SpellDps = 87, // spell_dps + SpellAntiMissMul = 88, // spell_anti_miss_mul + CastingTolerance = 89, // casting_tolerance + AggroMul = 90, // aggro_mul + LungCapacity = 91, // lung_capacity + FallDamageMul = 92, // fall_damage_mul + LadderSpeedMul = 93, // ladder_speed_mul + DetectStealthRangeMul = 94, // detect_stealth_range_mul + ExpMul = 95, // exp_mul + MainhandDps = 96, // mainhand_dps + OffhandDps = 97, // offhand_dps + RangedDps = 98, // ranged_dps + ActabilityArchemy = 99, // actability_archemy + ActabilityArchitecture = 100, // actability_architecture + ActabilityCook = 101, // actability_cook + ActabilityHandicraft = 102, // actability_handicraft + ActabilityLivestock = 103, // actability_livestock + ActabilityFarm = 104, // actability_farm + ActabilityFish = 105, // actability_fish + ActabilityLumber = 106, // actability_lumber + ActabilityCollection = 107, // actability_collection + ActabilityMachinery = 108, // actability_machinery + ActabilityMetal = 109, // actability_metal + ActabilityPrint = 110, // actability_print + ActabilityMine = 111, // actability_mine + ActabilityStonemason = 112, // actability_stonemason + ActabilitySewing = 113, // actability_sewing + ActabilitySkin = 114, // actability_skin + ActabilityWeapon = 115, // actability_weapon + ActabilityCarpentry = 116, // actability_carpentry + ActabilityTheft = 117, // actability_theft + ActabilityBusiness = 118, // actability_business + AttackAnimSpeedMul = 119, // attack_anim_speed_mul + HealMul = 120, // heal_mul + BackattackMeleeDamageMul = 121, // backattack_melee_damage_mul + BackattackRangedDamageMul = 122, // backattack_ranged_damage_mul + BackattackSpellDamageMul = 123, // backattack_spell_damage_mul + FrictionMul = 124, // friction_mul + HonorPointLoseMul = 125, // honor_point_lose_mul + HonorPointGainNpcKill = 128, // honor_point_gain_npc_kill + HonorPointGainNpcKillMul = 129, // honor_point_gain_npc_kill_mul + HonorPointGainTrial = 130, // honor_point_gain_trial + HonorPointGainTrialMul = 131, // honor_point_gain_trial_mul + HonorPointGainWar = 132, // honor_point_gain_war + HonorPointGainWarMul = 133, // honor_point_gain_war_mul + HonorPointGainQuest = 134, // honor_point_gain_quest + HonorPointGainQuestMul = 135, // honor_point_gain_quest_mul + LivingPointGain = 136, // living_point_gain + LivingPointGainMul = 137, // living_point_gain_mul + ActabilityComposition = 138, // actability_composition + UnderwaterSwimSpeedMul = 139, // underwater_swim_speed_mul + DropRateMul = 140, // drop_rate_mul + LootGoldMul = 141, // loot_gold_mul + IncomingMeleeDamageAdd = 142, // incoming_melee_damage_add + IncomingMeleeDamageMul = 143, // incoming_melee_damage_mul + IncomingRangedDamageAdd = 144, // incoming_ranged_damage_add + IncomingRangedDamageMul = 145, // incoming_ranged_damage_mul + IncomingSpellDamageAdd = 146, // incoming_spell_damage_add + IncomingSpellDamageMul = 147, // incoming_spell_damage_mul + IncomingSiegeDamageAdd = 148, // incoming_siege_damage_add + IncomingSiegeDamageMul = 149, // incoming_siege_damage_mul + SpellDamageCritical = 150, // spell_damage_critical + SpellDamageCriticalMul = 151, // spell_damage_critical_mul + SpellDamageCriticalBonus = 152, // spell_damage_critical_bonus + RangedParry = 153, // ranged_parry + RangedParryMul = 154, // ranged_parry_mul + DeathDurabilityLossRatioMul = 155, // death_durability_loss_ratio_mul + PenaltyExpMul = 156, // penalty_exp_mul + RecoverableExpMul = 157, // recoverable_exp_mul + ActabilityLangNuian = 158, // actability_lang_nuian + ActabilityLangElf = 159, // actability_lang_elf + ActabilityLangHariharan = 160, // actability_lang_hariharan + ActabilityLangFerre = 161, // actability_lang_ferre + ActabilityLangWestcommon = 162, // actability_lang_westcommon + ActabilityLangEastcommon = 163, // actability_lang_eastcommon + ActabilityLangDwarf = 164, // actability_lang_dwarf + ActabilityLangWarborn = 165, // actability_lang_warborn + HealDps = 173, // heal_dps + HealCritical = 174, // heal_critical + HealDpsInc = 175, // heal_dps_inc + HealCriticalBonus = 176, // heal_critical_bonus + Block = 177, // block + Dodge = 178, // dodge + BlockMul = 179, // block_mul + DodgeMul = 180, // dodge_mul + BullsEye = 181, // bulls_eye + BattleResist = 182, // battle_resist + Flexibility = 183, // flexibility + MagicPenetration = 184, // magic_penetration + HealCriticalMul = 185, // heal_critical_mul + ExpByLaborPowerMul = 186, // exp_by_labor_power_mul + PhysicsCollisionDamageMul = 187, // physics_collision_damage_mul + Mass = 188, // mass + MassMul = 189, // mass_mul + SteeringSpeed = 190, // steering_speed + SteeringSpeedMul = 191, // steering_speed_mul + ReverseVelocity = 192, // reverse_velocity + ReverseVelocityMul = 193, // reverse_velocity_mul + PhysicsCollisionArmorMul = 194, // physics_collision_armor_mul + ActabilityExploration = 195, // actability_exploration + MeleeDamageMulAntiNpc = 196, // melee_damage_mul_anti_npc + RangedDamageMulAntiNpc = 197, // ranged_damage_mul_anti_npc + SpellDamageMulAntiNpc = 198, // spell_damage_mul_anti_npc + IncomingDamageMulAntiNpc = 199, // incoming_damage_mul_anti_npc + IncomingMeleeDamageAddAntiNpc = 200, // incoming_melee_damage_add_anti_npc + IncomingRangedDamageAddAntiNpc = 201, // incoming_ranged_damage_add_anti_npc + IncomingSpellDamageAddAntiNpc = 202, // incoming_spell_damage_add_anti_npc + ImpactMass = 203, // impact_mass + IgnoreShieldChance = 204, // ignore_shield_chance + IgnoreShieldBonus = 205, // ignore_shield_bonus + IgnoreShieldBonusMul = 206, // ignore_shield_bonus_mul + MeleeDynamicNormalizable = 207, // melee_dynamic_normalizable + RangedDynamicNormalizable = 208, // ranged_dynamic_normalizable + MagicDynamicNormalizable = 209, // magic_dynamic_normalizable + HealDynamicNormalizable = 210, // heal_dynamic_normalizable + DefenceDynamicNormalizable = 211, // defence_dynamic_normalizable + MusicDynamicNormalizable = 212, // music_dynamic_normalizable + MaxHighAbilityResource = 215, // max_high_ability_resource + HighAbilityResourceRegen = 216, // high_ability_resource_regen + PersistentHighAbilityResourceRegen = 217, // persistent_high_ability_resource_regen + AttackSpeedMul = 218, // attack_speed_mul + SubmergeDepth = 219, // submerge_depth + ExpByKillMonsterMul = 220 // exp_by_kill_monster_mul } diff --git a/AAEmu.Game/Models/Game/Units/UnitReqs.cs b/AAEmu.Game/Models/Game/Units/UnitReqs.cs index b638eeb29d..d553aa8038 100644 --- a/AAEmu.Game/Models/Game/Units/UnitReqs.cs +++ b/AAEmu.Game/Models/Game/Units/UnitReqs.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; + using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Managers.World; using AAEmu.Game.GameData; @@ -14,7 +15,6 @@ using AAEmu.Game.Models.Game.Skills; using AAEmu.Game.Models.Game.Skills.Static; using AAEmu.Game.Models.Game.Units.Static; -using AAEmu.Game.Models.Game.World.Zones; namespace AAEmu.Game.Models.Game.Units; diff --git a/AAEmu.Game/Models/Game/World/Zones/IndunZone.cs b/AAEmu.Game/Models/Game/World/Zones/IndunZone.cs index 5e1a0fe4aa..7eaf444362 100644 --- a/AAEmu.Game/Models/Game/World/Zones/IndunZone.cs +++ b/AAEmu.Game/Models/Game/World/Zones/IndunZone.cs @@ -16,12 +16,12 @@ public class IndunZone public bool ClientDriven { get; set; } public bool SelectChannel { get; set; } public string LocalizedName { get; set; } - public bool Pvp { get; set; } public uint VictoryTargetNpc { get; set; } public bool CanUseForceAttack { get; set; } public bool Duel { get; set; } public bool ExpPanelty { get; set; } public uint GearScore { get; set; } + public uint EnterCount { get; set; } public override string ToString() { diff --git a/AAEmu.Game/Models/Tasks/CashShop/CashShopBuyTask.cs b/AAEmu.Game/Models/Tasks/CashShop/CashShopBuyTask.cs index 119d14fa3e..d8eb7557ec 100644 --- a/AAEmu.Game/Models/Tasks/CashShop/CashShopBuyTask.cs +++ b/AAEmu.Game/Models/Tasks/CashShop/CashShopBuyTask.cs @@ -255,7 +255,7 @@ public override void Execute() AccountManager.Instance.AddLoyalty(_buyer.AccountId, (int)(sku.Price * -1)); break; case CashShopCurrencyType.Coins: - if (!_buyer.SubtractMoney(SlotType.Inventory, (int)sku.Price, ItemTaskType.StoreBuy)) + if (!_buyer.SubtractMoney(SlotType.Bag, (int)sku.Price, ItemTaskType.StoreBuy)) Logger.Error($"Sale validation failed for {_buyer.Name}, {sku.Currency} x {sku.Price}"); break; default: diff --git a/AAEmu.Game/Models/Tasks/Characters/CharacterOnlineTrackingTask.cs b/AAEmu.Game/Models/Tasks/Characters/CharacterOnlineTrackingTask.cs index 9fd6b36a96..c90941070c 100644 --- a/AAEmu.Game/Models/Tasks/Characters/CharacterOnlineTrackingTask.cs +++ b/AAEmu.Game/Models/Tasks/Characters/CharacterOnlineTrackingTask.cs @@ -1,9 +1,10 @@ using System; +using System.Collections.Generic; + using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Packets.G2C; -using AAEmu.Game.Models.Game; -using AAEmu.Game.Models.Game.Items.Actions; +using AAEmu.Game.Models.Game.Char; namespace AAEmu.Game.Models.Tasks.Characters; @@ -13,6 +14,7 @@ public class CharacterOnlineTrackingTask : Task private DateTime LastCheck { get; set; } private readonly object _lock = new(); private bool Busy { get; set; } + private Dictionary last60SecondCheck = new(); public CharacterOnlineTrackingTask() { @@ -29,6 +31,7 @@ public override void Execute() return; Busy = true; } + var delta = DateTime.UtcNow - LastCheck; LastCheck = DateTime.UtcNow; @@ -40,27 +43,32 @@ public override void Execute() character.OnlineTime += delta; var newSeconds = Math.Floor(character.OnlineTime.TotalSeconds); var deltaSeconds = (uint)(newSeconds - lastSeconds); - - // Update Account Divine Clock time - var (time, taken) = AccountManager.Instance.GetDivineClock(character.AccountId); - time += deltaSeconds; - AccountManager.Instance.UpdateDivineClock(character.AccountId, time, taken); - // TODO: Use lastSeconds and newSeconds as a comparison for triggering time played achievements // TODO: Add divine clock feedback packets - - if (time % 60 == 0) + // Check if 60 seconds have passed since the last 60-second check + if (last60SecondCheck.TryGetValue(character.AccountId, out var lastCheckTime)) { - var si = new ScheduleItem + var elapsedTime = DateTime.UtcNow - lastCheckTime; + if (elapsedTime.TotalSeconds >= 60) { - ItemTemplateId = 9000003, - Gave = (byte)taken, - Acumulated = time, - Updated = DateTime.UtcNow - }; - character.SendPacket(new SCScheduleItemUpdatePacket([si])); - character.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.Unk136, [], [])); + //// Check if 1 hour has passed + //if (character.OnlineTime.TotalHours >= 1) + //{ + // // Perform additional work when 1 hour is reached + // PerformHourlyCalculations(character); + //} + + // Perform 60-second calculations + Perform60SecondCalculations(character, deltaSeconds); + // Update the last 60-second check time + last60SecondCheck[character.AccountId] = DateTime.UtcNow; + } + } + else + { + // Initialize the last 60-second check time + last60SecondCheck[character.AccountId] = DateTime.UtcNow; } } @@ -69,4 +77,38 @@ public override void Execute() Busy = false; } } + + private void Perform60SecondCalculations(Character character, uint deltaSeconds) + { + // You can add any other 60-second calculations you need here + for (var index = 0; index < character.ScheduleItems.Count; index++) + { + var scheduleItem = AccountManager.Instance.GetDivineClock(character.AccountId, character.ScheduleItems[index].ScheduleItemId); + if (scheduleItem is not null) + { + character.ScheduleItems[index] = scheduleItem; // updated + } + + var si = GameScheduleManager.Instance.GetScheduleItem(character.ScheduleItems[index].ScheduleItemId); + if (character.ScheduleItems[index].Gave == si.GiveMax) + { + character.ScheduleItems[index].Cumulated = 0; + } + else + { + character.ScheduleItems[index].Cumulated += 60; + } + + character.ScheduleItems[index].Updated = DateTime.UtcNow; + + // Update Account Divine Clock time + AccountManager.Instance.UpdateDivineClock(character.AccountId, character.ScheduleItems[index].ScheduleItemId, character.ScheduleItems[index].Cumulated, character.ScheduleItems[index].Gave); + character.SendPacket(new SCScheduleItemUpdatePacket(character.ScheduleItems)); + } + } + + private void PerformHourlyCalculations(Character character) + { + // You can add any other hourly calculations you need here + } } diff --git a/AAEmu.Game/Scripts/Commands/AddPortals.cs b/AAEmu.Game/Scripts/Commands/AddPortals.cs index bb31e7ce94..90589b1661 100644 --- a/AAEmu.Game/Scripts/Commands/AddPortals.cs +++ b/AAEmu.Game/Scripts/Commands/AddPortals.cs @@ -70,7 +70,8 @@ public void Execute(Character character, string[] args, IMessageOutput messageOu zRot = 0; } - targetPlayer.Portals.AddPrivatePortal(x, y, z, zRot, zoneId, portalName); + //targetPlayer.Portals.AddPrivatePortal(x, y, z, zRot, zoneId, portalName); + targetPlayer.Portals.AddOrUpdatePrivatePortal(x, y, z, zRot, zoneId, portalName); if (character.Id != targetPlayer.Id) { CommandManager.SendNormalText(this, messageOutput, diff --git a/AAEmu.Game/Scripts/Commands/ShowInventory.cs b/AAEmu.Game/Scripts/Commands/ShowInventory.cs index b64bb6314b..ca714151e4 100644 --- a/AAEmu.Game/Scripts/Commands/ShowInventory.cs +++ b/AAEmu.Game/Scripts/Commands/ShowInventory.cs @@ -72,11 +72,11 @@ public void Execute(Character character, string[] args, IMessageOutput messageOu targetPlayer = WorldManager.GetTargetOrSelf(character, args[0], out firstarg); } - var containerId = SlotType.Inventory; + var containerId = SlotType.Bag; if (args.Length > firstarg + 0 && uint.TryParse(args[firstarg + 0], out var argcontainerId)) { - if (argcontainerId <= (byte)SlotType.Mail || argcontainerId == (byte)SlotType.System) + if (argcontainerId <= (byte)SlotType.MailAttachment || argcontainerId == (byte)SlotType.Money) { containerId = (SlotType)argcontainerId; } @@ -93,7 +93,7 @@ public void Execute(Character character, string[] args, IMessageOutput messageOu if (targetPlayer.Inventory._itemContainers.TryGetValue(containerId, out var targetContainer)) { var showWarnings = targetContainer.ContainerType == SlotType.Equipment || - targetContainer.ContainerType == SlotType.Inventory || + targetContainer.ContainerType == SlotType.Bag || targetContainer.ContainerType == SlotType.Bank; var lastSlotNumber = -1; var hasSlotErrors = 0; diff --git a/AAEmu.Game/Scripts/Commands/TestAuctionHouse.cs b/AAEmu.Game/Scripts/Commands/TestAuctionHouse.cs index 0ae21dad63..0ea1b2eec4 100644 --- a/AAEmu.Game/Scripts/Commands/TestAuctionHouse.cs +++ b/AAEmu.Game/Scripts/Commands/TestAuctionHouse.cs @@ -1,9 +1,12 @@ -using System; +//using System; using AAEmu.Game.Core.Managers; +//using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Models.Game; using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Auction; +//using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Utils.Scripts; +//using AAEmu.Game.Models.Game.Items.Actions; namespace AAEmu.Game.Scripts.Commands; @@ -29,43 +32,26 @@ public string GetCommandHelpText() public void Execute(Character character, string[] args, IMessageOutput messageOutput) { var allItems = ItemManager.Instance.GetAllItems(); - CommandManager.SendNormalText(this, messageOutput, - $"Trying to add {allItems.Count} items to the Auction House!"); + CommandManager.SendNormalText(this, messageOutput, $"Trying to add {allItems.Count} items to the Auction House!"); var amount = 0; - foreach (var item in allItems) + foreach (var itemTemplate in allItems) { - var newAuctionItem = new AuctionItem + if (itemTemplate == null) { - Id = AuctionManager.Instance.GetNextId(), - Duration = 5, - ItemId = item.Id, - ObjectId = 0, - Grade = 0, - Flags = 0, - StackSize = 1, - DetailType = 0, - CreationTime = DateTime.UtcNow, - EndTime = DateTime.UtcNow.AddSeconds(172800), - LifespanMins = 0, - Type1 = 0, - WorldId = 0, - UnpackDateTime = DateTime.UtcNow, - UnsecureDateTime = DateTime.UtcNow, - WorldId2 = 0, - ClientId = 0, - ClientName = "", - StartMoney = 0, - DirectMoney = 1, - BidWorldId = 0, - BidderId = 0, - BidderName = "", - BidMoney = 0, - Extra = 0, - IsDirty = true - }; + continue; + } - AuctionManager.Instance.AddAuctionItem(newAuctionItem); + var item = ItemManager.Instance.Create(itemTemplate.Id, 1, 0); + if (item == null) + { + continue; + } + // Create a new auction item + var newAuctionItem = AuctionManager.Instance.CreateAuctionLot(character, item, 0, 1, AuctionDuration.AuctionDuration6Hours, 1, 1); + + // Add the auction item to the auction house + AuctionManager.Instance.AddAuctionLot(newAuctionItem); amount++; } diff --git a/AAEmu.Game/Scripts/Commands/TestMails.cs b/AAEmu.Game/Scripts/Commands/TestMails.cs index bfd584221b..1d46fac4ce 100644 --- a/AAEmu.Game/Scripts/Commands/TestMails.cs +++ b/AAEmu.Game/Scripts/Commands/TestMails.cs @@ -6,6 +6,7 @@ using AAEmu.Game.Models.Game.Chat; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; using AAEmu.Game.Utils.Scripts; namespace AAEmu.Game.Scripts.Commands; @@ -203,7 +204,7 @@ public void Execute(Character character, string[] args, IMessageOutput messageOu var newItem = ItemManager.Instance.Create(itemId, itemCount, (byte)itemGrade, true); newItem.OwnerId = character.Id; - newItem.SlotType = SlotType.Mail; + newItem.SlotType = SlotType.MailAttachment; mail.Body.Attachments.Add(newItem); CommandManager.SendNormalText(this, messageOutput, diff --git a/AAEmu.Game/Scripts/Commands/WipeAuctionHouse.cs b/AAEmu.Game/Scripts/Commands/WipeAuctionHouse.cs index afbe79dc23..7e05d5e0fa 100644 --- a/AAEmu.Game/Scripts/Commands/WipeAuctionHouse.cs +++ b/AAEmu.Game/Scripts/Commands/WipeAuctionHouse.cs @@ -35,12 +35,12 @@ public void Execute(Character character, string[] args, IMessageOutput messageOu AuctionManager.Instance.Load(); - foreach (var item in AuctionManager.Instance._auctionItems) + foreach (var item in AuctionManager.Instance.AuctionLots) { AuctionManager.Instance._deletedAuctionItemIds.Add((long)item.Id); } - AuctionManager.Instance._auctionItems.Clear(); + AuctionManager.Instance.AuctionLots.Clear(); SaveManager.Instance.DoSave(); AuctionManager.Instance.Load(); } diff --git a/AAEmu.Game/Services/WebApi/Controllers/AuctionController.cs b/AAEmu.Game/Services/WebApi/Controllers/AuctionController.cs index 44eb3b0791..fc68a0d641 100644 --- a/AAEmu.Game/Services/WebApi/Controllers/AuctionController.cs +++ b/AAEmu.Game/Services/WebApi/Controllers/AuctionController.cs @@ -1,14 +1,20 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Net; +using System.Numerics; +using System.Text.Json; +using System.Text.RegularExpressions; +using System.Web; + using AAEmu.Game.Core.Managers; +using AAEmu.Game.Core.Managers.Id; +using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Models.Game.Auction; +using AAEmu.Game.Models.Game.Char; +using AAEmu.Game.Models.Game.Items; + using NetCoreServer; -using System.Text.Json; -using System.Text.RegularExpressions; + using NLog; -using System.Web; namespace AAEmu.Game.Services.WebApi.Controllers { @@ -37,48 +43,27 @@ public HttpResponse AddAuctionItem(HttpRequest request, MatchCollection matches) } var itemId = itemIdElement.GetUInt32(); - var quantity = quantityElement.GetUInt32(); + var quantity = quantityElement.GetInt32(); var price = priceElement.GetInt32(); - var duration = durationElement.GetInt32(); + var duration = (AuctionDuration)durationElement.GetInt32(); var clientId = clientIdElement.GetUInt32(); var clientName = clientNameElement.GetString(); try { - // Create a new auction item - var newAuctionItem = new AuctionItem + var player = WorldManager.Instance.GetCharacterById(clientId); + var item = ItemManager.Instance.GetItemByItemId(itemId); + if (player == null || item == null) { - Id = AuctionManager.Instance.GetNextId(), - Duration = (byte)duration, - ItemId = itemId, - ObjectId = 0, - Grade = 0, - Flags = 0, - StackSize = quantity, - DetailType = 0, - CreationTime = DateTime.UtcNow, - EndTime = DateTime.UtcNow.AddSeconds(duration), - LifespanMins = 0, - Type1 = 0, - WorldId = 0, - UnpackDateTime = DateTime.UtcNow, - UnsecureDateTime = DateTime.UtcNow, - WorldId2 = 0, - ClientId = clientId, - ClientName = clientName, - StartMoney = 0, - DirectMoney = price, - BidWorldId = 0, - BidderId = 0, - BidderName = "", - BidMoney = 0, - Extra = 0, - IsDirty = true - }; + return BadRequestJson(new { error = "Internal server error", details = "Item not found!" }); + } + // Create a new auction item + var newAuctionItem = AuctionManager.Instance.CreateAuctionLot(player, item, price, price, duration, 1, quantity); // Add the auction item to the auction house - AuctionManager.Instance.AddAuctionItem(newAuctionItem); + AuctionManager.Instance.AddAuctionLot(newAuctionItem); Logger.Info($"Added auction item: {newAuctionItem}"); + return OkJson(new { message = "Auction item added successfully", item = newAuctionItem }); } catch (Exception ex) @@ -94,7 +79,7 @@ public HttpResponse GetAllAuctionItems(HttpRequest request, MatchCollection matc { try { - var auctionItems = AuctionManager.Instance._auctionItems; + var auctionItems = AuctionManager.Instance.AuctionLots; return OkJson(new { items = auctionItems }); } catch (Exception ex) @@ -111,7 +96,7 @@ public HttpResponse SearchAuctionItems(HttpRequest request, MatchCollection matc { try { - var query = AuctionManager.Instance._auctionItems.AsQueryable(); + var query = AuctionManager.Instance.AuctionLots.AsQueryable(); // Extract query parameters from the URL var queryParams = HttpUtility.ParseQueryString(request.Url.Split('?').Length > 1 ? request.Url.Split('?')[1] : ""); @@ -119,32 +104,32 @@ public HttpResponse SearchAuctionItems(HttpRequest request, MatchCollection matc // Apply filters if (queryParams["itemId"] != null) { - uint itemId = uint.Parse(queryParams["itemId"]); - query = query.Where(item => item.ItemId == itemId); + var itemId = uint.Parse(queryParams["itemId"]); + query = query.Where(item => item.Item.TemplateId == itemId); } if (queryParams["clientName"] != null) { - string clientName = queryParams["clientName"]; + var clientName = queryParams["clientName"]; query = query.Where(item => item.ClientName.Equals(clientName, StringComparison.OrdinalIgnoreCase)); } if (queryParams["stackSize"] != null) { - uint stackSize = uint.Parse(queryParams["stackSize"]); - query = query.Where(item => item.StackSize == stackSize); + var stackSize = uint.Parse(queryParams["stackSize"]); + query = query.Where(item => item.Item.Count == stackSize); } if (queryParams["directMoney"] != null) { - int directMoney = int.Parse(queryParams["directMoney"]); + var directMoney = int.Parse(queryParams["directMoney"]); query = query.Where(item => item.DirectMoney == directMoney); } if (queryParams["bidMoney"] != null) { - int bidMoney = int.Parse(queryParams["bidMoney"]); + var bidMoney = int.Parse(queryParams["bidMoney"]); query = query.Where(item => item.BidMoney == bidMoney); } if (queryParams["bidderName"] != null) { - string bidderName = queryParams["bidderName"]; + var bidderName = queryParams["bidderName"]; query = query.Where(item => item.BidderName.Equals(bidderName, StringComparison.OrdinalIgnoreCase)); } diff --git a/AAEmu.Game/Services/WebApi/Controllers/MailController.cs b/AAEmu.Game/Services/WebApi/Controllers/MailController.cs index 803f361105..67247121c6 100644 --- a/AAEmu.Game/Services/WebApi/Controllers/MailController.cs +++ b/AAEmu.Game/Services/WebApi/Controllers/MailController.cs @@ -7,6 +7,7 @@ using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; using AAEmu.Game.Models.Game.Units; using AAEmu.Game.Models.StaticValues; using AAEmu.Game.Services.WebApi.Models; @@ -180,7 +181,7 @@ public HttpResponse Send(HttpRequest request) mail.Title = mailRequest.Title; mail.ReceiverName = character.Name; - mail.Header.SenderId = 0; + mail.Header.SenderId = (uint)SystemMailSenderKind.None; mail.Header.SenderName = mailRequest.SenderName; mail.Header.ReceiverId = character.Id; @@ -214,7 +215,7 @@ public HttpResponse Send(HttpRequest request) var newItem = ItemManager.Instance.Create(itemTemplate.Id, attachmentItem.Count, (byte)itemGrade); newItem.OwnerId = character.Id; - newItem.SlotType = SlotType.Mail; + newItem.SlotType = SlotType.MailAttachment; mail.Body.Attachments.Add(newItem); } diff --git a/AAEmu.Game/Services/WebApi/Models/SendMailRequest.cs b/AAEmu.Game/Services/WebApi/Models/SendMailRequest.cs index 99d63c4875..c8e5c2f9e3 100644 --- a/AAEmu.Game/Services/WebApi/Models/SendMailRequest.cs +++ b/AAEmu.Game/Services/WebApi/Models/SendMailRequest.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Services.WebApi.Models; diff --git a/AAEmu.Login/Core/Controllers/LoginController.cs b/AAEmu.Login/Core/Controllers/LoginController.cs index 9d3ec594b7..2e7a409642 100644 --- a/AAEmu.Login/Core/Controllers/LoginController.cs +++ b/AAEmu.Login/Core/Controllers/LoginController.cs @@ -56,7 +56,7 @@ public static void Login(LoginConnection connection, string username) connection.LastLogin = DateTime.UtcNow; connection.LastIp = connection.Ip; - connection.SendPacket(new ACJoinResponsePacket(0, 0, 0x0B0202, 0)); + connection.SendPacket(new ACJoinResponsePacket(0, 0, 0x220101, 0)); connection.SendPacket(new ACAuthResponsePacket(connection.AccountId, 0)); reader.Close(); @@ -125,7 +125,7 @@ public static void Login(LoginConnection connection, string username, IEnumerabl connection.LastIp = connection.Ip; Logger.Info("{0} connected.", connection.AccountName); - connection.SendPacket(new ACJoinResponsePacket(0, 0, 0x0B0202, 0)); + connection.SendPacket(new ACJoinResponsePacket(0, 0, 0x360404, 0)); connection.SendPacket(new ACAuthResponsePacket(connection.AccountId, 0)); reader.Close(); @@ -213,7 +213,7 @@ public void Reconnect(LoginConnection connection, byte gsId, ulong accountId, ui if (_tokens[gsId][token] == accountId) { connection.AccountId = accountId; - connection.SendPacket(new ACJoinResponsePacket(0, 0, 0x0B0202, 0)); + connection.SendPacket(new ACJoinResponsePacket(0, 0, 0x360404, 0)); connection.SendPacket(new ACAuthResponsePacket(connection.AccountId, 0)); } else diff --git a/AAEmu.UnitTests/Game/Core/Managers/MailTests.cs b/AAEmu.UnitTests/Game/Core/Managers/MailTests.cs index d97d9ed72f..e5362d6fb8 100644 --- a/AAEmu.UnitTests/Game/Core/Managers/MailTests.cs +++ b/AAEmu.UnitTests/Game/Core/Managers/MailTests.cs @@ -5,6 +5,7 @@ using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; using AAEmu.Game.Models.Game.Units; using AAEmu.UnitTests.Utils.Mocks; using Xunit; diff --git a/AAEmu.UnitTests/Game/Models/Game/Items/Containers/InventoryTests.cs b/AAEmu.UnitTests/Game/Models/Game/Items/Containers/InventoryTests.cs index a33cdcfebf..443438af87 100644 --- a/AAEmu.UnitTests/Game/Models/Game/Items/Containers/InventoryTests.cs +++ b/AAEmu.UnitTests/Game/Models/Game/Items/Containers/InventoryTests.cs @@ -16,7 +16,7 @@ public void InventoryAddsItem() // ItemIdManager.Instance.Initialize(); var mockCharacter = new CharacterMock(); - var container = new ItemContainer(mockCharacter.Id, SlotType.Inventory, false, mockCharacter); + var container = new ItemContainer(mockCharacter.Id, SlotType.Bag, false, mockCharacter); var item = InventoryTestUtils.MockItem(1, 1); Assert.True(container.AddOrMoveExistingItem(ItemTaskType.Gm, item, 1)); diff --git a/Docs/Docker-Installation-Guide.md b/Docs/Docker-Installation-Guide.md index 38b28c6fe9..1d280b7eed 100644 --- a/Docs/Docker-Installation-Guide.md +++ b/Docs/Docker-Installation-Guide.md @@ -4,7 +4,7 @@ We made this little docker installation script in powershell or bash - depending - New people to this project who wants a server to run quicker and with less headache even if it's easy if you know your basics. ## Prerequisites -Get the **compact.sqlite3** server database and the **game_pak** of the ArcheAge client version you are using. And put them where the script tell you too. +Get the **compact.sqlite3** server database ([Google Drive](https://drive.google.com/file/d/18Nm_Q7OgWOfdw_8Xl4TBXa1Z51uGHEIh/view) or [MEGA](https://mega.nz/file/ujhFAaIS#disveSrjdUVjY9mZ3Q2xJ2b7I4te2gwbKnzMYD8HLZ4)) and the **game_pak** of the ArcheAge client version you are using. And put them where the script tell you too. **Windows**: - Git : https://git-scm.com/downloads diff --git a/SQL/aaemu_game.sql b/SQL/aaemu_game.sql index c6baedae88..e442737ef9 100644 --- a/SQL/aaemu_game.sql +++ b/SQL/aaemu_game.sql @@ -1,40 +1,54 @@ -CREATE DATABASE IF NOT EXISTS `aaemu_game_5070`; -USE aaemu_game_5070; --- ---------------------------------------------------------------------------------------------- --- Make sure to remove the above two lines if you want use your own DB/Schema names during import --- ---------------------------------------------------------------------------------------------- +/* + Navicat Premium Data Transfer -SET NAMES utf8; -SET time_zone = '+00:00'; -SET foreign_key_checks = 0; + Source Server : archeage + Source Server Type : MySQL + Source Server Version : 80033 + Source Host : localhost:3306 + Source Schema : aaemu_game_5070 + Target Server Type : MySQL + Target Server Version : 80033 + File Encoding : 65001 + Date: 16/09/2024 02:14:42 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for abilities +-- ---------------------------- DROP TABLE IF EXISTS `abilities`; -CREATE TABLE `abilities` ( - `id` tinyint unsigned NOT NULL, +CREATE TABLE `abilities` ( + `id` tinyint UNSIGNED NOT NULL, `exp` int NOT NULL, - `owner` int unsigned NOT NULL, - PRIMARY KEY (`id`,`owner`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Skillsets Exp'; - + `owner` int UNSIGNED NOT NULL, + PRIMARY KEY (`id`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Skillsets Exp' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for accounts +-- ---------------------------- DROP TABLE IF EXISTS `accounts`; -CREATE TABLE `accounts` ( - `account_id` BIGINT UNSIGNED NOT NULL, - `access_level` INT(11) NOT NULL DEFAULT '0', - `labor` INT(11) NOT NULL DEFAULT '0', - `credits` INT(11) NOT NULL DEFAULT '0', - `loyalty` INT(11) NOT NULL DEFAULT '0', - `last_updated` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - `last_login` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - `last_labor_tick` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - `last_credits_tick` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - `last_loyalty_tick` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - `divine_clock_time` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Time that has been passed already', - `divine_clock_taken` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Number of clicks taken today', - PRIMARY KEY (`account_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Account specific values not related to login'; +CREATE TABLE `accounts` ( + `account_id` bigint UNSIGNED NOT NULL, + `access_level` int NOT NULL DEFAULT 0, + `labor` int NOT NULL DEFAULT 0, + `credits` int NOT NULL DEFAULT 0, + `loyalty` int NOT NULL DEFAULT 0, + `last_updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_login` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_labor_tick` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_credits_tick` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_loyalty_tick` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`account_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Account specific values not related to login' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Triggers structure for table accounts +-- ---------------------------- DELIMITER // CREATE TRIGGER update_timestamps @@ -46,71 +60,124 @@ END; // DELIMITER ; - +-- ---------------------------- +-- Table structure for actabilities +-- ---------------------------- DROP TABLE IF EXISTS `actabilities`; -CREATE TABLE `actabilities` ( - `id` int unsigned NOT NULL, - `point` int unsigned NOT NULL DEFAULT '0', - `step` tinyint unsigned NOT NULL DEFAULT '0', - `owner` int unsigned NOT NULL, - PRIMARY KEY (`owner`,`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Vocations'; - +CREATE TABLE `actabilities` ( + `id` int UNSIGNED NOT NULL, + `point` int UNSIGNED NOT NULL DEFAULT 0, + `step` tinyint UNSIGNED NOT NULL DEFAULT 0, + `owner` int UNSIGNED NOT NULL, + PRIMARY KEY (`owner`, `id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Vocations' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for appellations +-- ---------------------------- DROP TABLE IF EXISTS `appellations`; -CREATE TABLE `appellations` ( - `id` int unsigned NOT NULL, - `active` tinyint(1) NOT NULL DEFAULT '0', - `owner` int unsigned NOT NULL, - PRIMARY KEY (`id`,`owner`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Earned titles'; +CREATE TABLE `appellations` ( + `id` int UNSIGNED NOT NULL, + `active` tinyint(1) NOT NULL DEFAULT 0, + `owner` int UNSIGNED NOT NULL, + PRIMARY KEY (`id`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Earned titles' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for attendances +-- ---------------------------- +DROP TABLE IF EXISTS `attendances`; +CREATE TABLE `attendances` ( + `id` tinyint UNSIGNED NOT NULL, + `owner` bigint UNSIGNED NOT NULL, + `account_attendance` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', + `accept` tinyint(1) NOT NULL, + PRIMARY KEY (`id`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; +-- ---------------------------------- +-- Table structure for auction_house +-- ---------------------------------- DROP TABLE IF EXISTS `auction_house`; -CREATE TABLE `auction_house` ( - `id` int NOT NULL AUTO_INCREMENT, +CREATE TABLE `auction_house` ( + `id` bigint NOT NULL AUTO_INCREMENT, `duration` tinyint NOT NULL, - `item_id` int NOT NULL, - `object_id` int NOT NULL, - `grade` tinyint(1) NOT NULL, - `flags` tinyint(1) NOT NULL, - `stack_size` int NOT NULL, - `detail_type` tinyint(1) NOT NULL, - `creation_time` datetime NOT NULL, + `item_id` bigint NOT NULL, `end_time` datetime NOT NULL, - `lifespan_mins` int NOT NULL, - `type_1` int NOT NULL, `world_id` tinyint NOT NULL, - `unsecure_date_time` varchar(45) NOT NULL, - `unpack_date_time` varchar(45) NOT NULL, - `world_id_2` tinyint NOT NULL, `client_id` int NOT NULL, - `client_name` varchar(45) NOT NULL, + `client_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `start_money` int NOT NULL, `direct_money` int NOT NULL, - `bid_world_id` tinyint(1) NOT NULL, + `charge_percent` int NOT NULL, + `bid_world_id` int NOT NULL, `bidder_id` int NOT NULL, - `bidder_name` varchar(45) NOT NULL, + `bidder_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `bid_money` int NOT NULL, `extra` int NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Listed AH Items'; + `min_stack` int NOT NULL, + `max_stack` int NOT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Listed AH Items' ROW_FORMAT = DYNAMIC; +-- ---------------------------- +-- Table structure for auction_solds_data +-- ---------------------------- +DROP TABLE IF EXISTS `auction_solds_data`; +CREATE TABLE auction_solds_data ( + item_id INT UNSIGNED NOT NULL, + item_grade TINYINT NOT NULL, + date datetime NOT NULL, + min_copper BIGINT NOT NULL, + max_copper BIGINT NOT NULL, + avg_copper BIGINT NOT NULL, + volume INT NOT NULL, + weekly_avg_copper BIGINT NOT NULL, + PRIMARY KEY (item_id, item_grade, date) +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for audit_ics_sales +-- ---------------------------- +DROP TABLE IF EXISTS `audit_ics_sales`; +CREATE TABLE `audit_ics_sales` ( + `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, + `buyer_account` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Account ID of the person buying this item', + `buyer_char` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Character that was logged in when buying', + `target_account` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Account of the person receiving the goods', + `target_char` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Character that received the goods', + `sale_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Time of purchase (in UTC)', + `shop_item_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Shop item entry id of the sold item', + `sku` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'SKU of the sold item', + `sale_cost` int NOT NULL DEFAULT 0 COMMENT 'Amount this item was sold for', + `sale_currency` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Which currency was used', + `description` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT 'Added description of this transaction', + PRIMARY KEY (`id`) USING BTREE, + INDEX `buyer_account`(`buyer_account`) USING BTREE, + INDEX `buyer_char`(`buyer_char`) USING BTREE, + INDEX `target_account`(`target_account`) USING BTREE, + INDEX `target_char`(`target_char`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Sales history for the ICS' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for blocked +-- ---------------------------- DROP TABLE IF EXISTS `blocked`; -CREATE TABLE `blocked` ( +CREATE TABLE `blocked` ( `owner` int NOT NULL, `blocked_id` int NOT NULL, - PRIMARY KEY (`owner`,`blocked_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; - + PRIMARY KEY (`owner`, `blocked_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC; +-- ---------------------------- +-- Table structure for characters +-- ---------------------------- DROP TABLE IF EXISTS `characters`; -CREATE TABLE `characters` ( - `id` int unsigned NOT NULL, - `account_id` int unsigned NOT NULL, - `name` varchar(128) NOT NULL, - `access_level` int unsigned NOT NULL DEFAULT '0', +CREATE TABLE `characters` ( + `id` int UNSIGNED NOT NULL, + `account_id` int UNSIGNED NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `access_level` int UNSIGNED NOT NULL DEFAULT 0, `race` tinyint NOT NULL, `gender` tinyint(1) NOT NULL, `unit_model_params` blob NOT NULL, @@ -123,33 +190,33 @@ CREATE TABLE `characters` ( `ability1` tinyint NOT NULL, `ability2` tinyint NOT NULL, `ability3` tinyint NOT NULL, - `world_id` int unsigned NOT NULL, - `zone_id` int unsigned NOT NULL, + `world_id` int UNSIGNED NOT NULL, + `zone_id` int UNSIGNED NOT NULL, `x` float NOT NULL, `y` float NOT NULL, `z` float NOT NULL, - `yaw` float NOT NULL DEFAULT '0', - `pitch` float NOT NULL DEFAULT '0', - `roll` float NOT NULL DEFAULT '0', - `faction_id` int unsigned NOT NULL, - `faction_name` varchar(128) NOT NULL, + `yaw` float NOT NULL DEFAULT 0, + `pitch` float NOT NULL DEFAULT 0, + `roll` float NOT NULL DEFAULT 0, + `faction_id` int UNSIGNED NOT NULL, + `faction_name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `expedition_id` int NOT NULL, - `family` int unsigned NOT NULL, - `dead_count` mediumint unsigned NOT NULL, + `family` int UNSIGNED NOT NULL, + `dead_count` mediumint UNSIGNED NOT NULL, `dead_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `rez_wait_duration` int NOT NULL, `rez_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `rez_penalty_duration` int NOT NULL, `leave_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', - `money` bigint NOT NULL DEFAULT '0', - `money2` bigint NOT NULL DEFAULT '0', - `honor_point` int NOT NULL DEFAULT '0', - `vocation_point` int NOT NULL DEFAULT '0', - `crime_point` int NOT NULL DEFAULT '0', - `crime_record` int NOT NULL DEFAULT '0', - `jury_point` int NOT NULL DEFAULT '0', - `hostile_faction_kills` int NOT NULL DEFAULT '0', - `pvp_honor` int NOT NULL DEFAULT '0', + `money` bigint NOT NULL DEFAULT 0, + `money2` bigint NOT NULL DEFAULT 0, + `honor_point` int NOT NULL DEFAULT 0, + `vocation_point` int NOT NULL DEFAULT 0, + `crime_point` int NOT NULL DEFAULT 0, + `crime_record` int NOT NULL DEFAULT 0, + `jury_point` int NOT NULL DEFAULT 0, + `hostile_faction_kills` int NOT NULL DEFAULT 0, + `pvp_honor` int NOT NULL DEFAULT 0, `delete_request_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `transfer_request_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `delete_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', @@ -157,34 +224,38 @@ CREATE TABLE `characters` ( `prev_point` int NOT NULL, `point` int NOT NULL, `gift` int NOT NULL, - `num_inv_slot` tinyint unsigned NOT NULL DEFAULT '50', - `num_bank_slot` smallint unsigned NOT NULL DEFAULT '50', + `num_inv_slot` tinyint UNSIGNED NOT NULL DEFAULT 50, + `num_bank_slot` smallint UNSIGNED NOT NULL DEFAULT 50, `expanded_expert` tinyint NOT NULL, `slots` blob NOT NULL, - `created_at` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), - `updated_at` datetime(0) NOT NULL DEFAULT '0001-01-01 00:00:00', - `deleted` int(11) NOT NULL DEFAULT 0, - `return_district` int(11) NOT NULL DEFAULT 0, - `online_time` INT(11) NOT NULL DEFAULT 0 COMMENT 'Time that the character has been online', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', + `deleted` int NOT NULL DEFAULT 0, + `return_district` int NOT NULL DEFAULT 0, + `online_time` int NOT NULL DEFAULT 0 COMMENT 'Time that the character has been online', PRIMARY KEY (`id`, `account_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'Basic player character data' ROW_FORMAT = DYNAMIC; - +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Basic player character data' ROW_FORMAT = DYNAMIC; +-- ---------------------------- +-- Table structure for completed_quests +-- ---------------------------- DROP TABLE IF EXISTS `completed_quests`; -CREATE TABLE `completed_quests` ( - `id` int unsigned NOT NULL, +CREATE TABLE `completed_quests` ( + `id` int UNSIGNED NOT NULL, `data` tinyblob NOT NULL, - `owner` int unsigned NOT NULL, - PRIMARY KEY (`id`,`owner`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Quests marked as completed for character'; - + `owner` int UNSIGNED NOT NULL, + PRIMARY KEY (`id`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Quests marked as completed for character' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for doodads +-- ---------------------------- DROP TABLE IF EXISTS `doodads`; -CREATE TABLE `doodads` ( - `id` int unsigned NOT NULL AUTO_INCREMENT, - `owner_id` int DEFAULT NULL COMMENT 'Character DB Id', - `owner_type` tinyint unsigned DEFAULT '255', - `attach_point` int unsigned NULL DEFAULT '0' COMMENT 'Slot this doodad fits in on the owner', +CREATE TABLE `doodads` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `owner_id` int NULL DEFAULT NULL COMMENT 'Character DB Id', + `owner_type` tinyint UNSIGNED NULL DEFAULT 255, + `attach_point` int UNSIGNED NULL DEFAULT 0 COMMENT 'Slot this doodad fits in on the owner', `template_id` int NOT NULL, `current_phase_id` int NOT NULL, `plant_time` datetime NOT NULL, @@ -196,82 +267,86 @@ CREATE TABLE `doodads` ( `roll` float NOT NULL, `pitch` float NOT NULL, `yaw` float NOT NULL, - `scale` FLOAT NOT NULL DEFAULT '1' , - `item_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'Item DB Id of the associated item', - `house_id` int unsigned NOT NULL DEFAULT '0' COMMENT 'House DB Id if it is on actual house land', - `parent_doodad` int unsigned NOT NULL DEFAULT '0' COMMENT 'doodads DB Id this object is standing on', - `item_template_id` int unsigned NOT NULL DEFAULT '0' COMMENT 'ItemTemplateId of associated item', - `item_container_id` int unsigned NOT NULL DEFAULT '0' COMMENT 'ItemContainer Id for Coffers', - `data` int NOT NULL DEFAULT '0' COMMENT 'Doodad specific data', - `farm_type` int NOT NULL DEFAULT '0' COMMENT 'farm type for Public Farm', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Persistent doodads (e.g. tradepacks, furniture)'; + `scale` float NOT NULL DEFAULT 1, + `item_id` bigint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Item DB Id of the associated item', + `house_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'House DB Id if it is on actual house land', + `parent_doodad` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'doodads DB Id this object is standing on', + `item_template_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'ItemTemplateId of associated item', + `item_container_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'ItemContainer Id for Coffers', + `data` int NOT NULL DEFAULT 0 COMMENT 'Doodad specific data', + `farm_type` int NOT NULL DEFAULT 0 COMMENT 'farm type for Public Farm', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Persistent doodads (e.g. tradepacks, furniture)' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for expedition_applicants +-- ---------------------------- +DROP TABLE IF EXISTS `expedition_applicants`; +CREATE TABLE `expedition_applicants` ( + `expedition_id` int NOT NULL, + `character_id` int NOT NULL, + `character_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `character_level` tinyint(1) NOT NULL, + `memo` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `reg_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', + PRIMARY KEY (`expedition_id`, `character_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC; +-- ---------------------------- +-- Table structure for expedition_members +-- ---------------------------- DROP TABLE IF EXISTS `expedition_members`; -CREATE TABLE `expedition_members` ( +CREATE TABLE `expedition_members` ( `character_id` int NOT NULL, `expedition_id` int NOT NULL, - `name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `level` tinyint unsigned NOT NULL, - `role` tinyint unsigned NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `level` tinyint UNSIGNED NOT NULL, + `role` tinyint UNSIGNED NOT NULL, `last_leave_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - `ability1` tinyint unsigned NOT NULL, - `ability2` tinyint unsigned NOT NULL, - `ability3` tinyint unsigned NOT NULL, - `memo` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `ability1` tinyint UNSIGNED NOT NULL, + `ability2` tinyint UNSIGNED NOT NULL, + `ability3` tinyint UNSIGNED NOT NULL, + `memo` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, PRIMARY KEY (`character_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Guild members'; - - -DROP TABLE IF EXISTS `expedition_role_policies`; -CREATE TABLE `expedition_role_policies` ( - `expedition_id` int NOT NULL, - `role` tinyint unsigned NOT NULL, - `name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `dominion_declare` tinyint(1) NOT NULL, - `invite` tinyint(1) NOT NULL, - `expel` tinyint(1) NOT NULL, - `promote` tinyint(1) NOT NULL, - `dismiss` tinyint(1) NOT NULL, - `chat` tinyint(1) NOT NULL, - `manager_chat` tinyint(1) NOT NULL, - `siege_master` tinyint(1) NOT NULL, - `join_siege` tinyint(1) NOT NULL, - PRIMARY KEY (`expedition_id`,`role`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Guild role settings'; - +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Guild members' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for expedition_recruitments +-- ---------------------------- DROP TABLE IF EXISTS `expedition_recruitments`; CREATE TABLE `expedition_recruitments` ( `expedition_id` int NOT NULL, - `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `level` int NULL DEFAULT NULL, - `owner_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `introduce` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `owner_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `introduce` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `reg_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `end_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `member_count` int NULL DEFAULT NULL, `interest` int NULL DEFAULT NULL, `apply` tinyint(1) NOT NULL, PRIMARY KEY (`expedition_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'Guild recruitments'; - +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Guild recruitments' ROW_FORMAT = Dynamic; -- ---------------------------- --- Table structure for expedition_applicants +-- Table structure for expedition_role_policies -- ---------------------------- -DROP TABLE IF EXISTS `expedition_applicants`; -CREATE TABLE `expedition_applicants` ( +DROP TABLE IF EXISTS `expedition_role_policies`; +CREATE TABLE `expedition_role_policies` ( `expedition_id` int NOT NULL, - `character_id` int NOT NULL, - `character_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `character_level` tinyint(1) NOT NULL, - `memo` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `reg_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', - PRIMARY KEY (`expedition_id`, `character_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; - + `role` tinyint UNSIGNED NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `dominion_declare` tinyint(1) NOT NULL, + `invite` tinyint(1) NOT NULL, + `expel` tinyint(1) NOT NULL, + `promote` tinyint(1) NOT NULL, + `dismiss` tinyint(1) NOT NULL, + `chat` tinyint(1) NOT NULL, + `manager_chat` tinyint(1) NOT NULL, + `siege_master` tinyint(1) NOT NULL, + `join_siege` tinyint(1) NOT NULL, + PRIMARY KEY (`expedition_id`, `role`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Guild role settings' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for expeditions @@ -280,8 +355,8 @@ DROP TABLE IF EXISTS `expeditions`; CREATE TABLE `expeditions` ( `id` int NOT NULL, `owner` int NOT NULL DEFAULT 0, - `owner_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `owner_name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `mother` int NOT NULL DEFAULT 0, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `level` int NOT NULL DEFAULT 0, @@ -290,121 +365,187 @@ CREATE TABLE `expeditions` ( `war_deposit` int NOT NULL DEFAULT 0, `daily_exp` int NOT NULL DEFAULT 0, `last_exp_update_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', - `is_level_update` TINYINT(1) NOT NULL DEFAULT '0', + `is_level_update` tinyint(1) NOT NULL DEFAULT 0, `interest` int NOT NULL DEFAULT 0, - `motd_title` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `motd_content` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `motd_title` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `motd_content` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `win` int NOT NULL DEFAULT 0, `lose` int NOT NULL DEFAULT 0, `draw` int NOT NULL DEFAULT 0, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'Guilds' ROW_FORMAT = Dynamic; - +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Guilds' ROW_FORMAT = DYNAMIC; +-- ---------------------------- +-- Table structure for family_members +-- ---------------------------- DROP TABLE IF EXISTS `family_members`; -CREATE TABLE `family_members` ( +CREATE TABLE `family_members` ( `character_id` int NOT NULL, `family_id` int NOT NULL, - `name` varchar(45) NOT NULL, - `role` tinyint(1) NOT NULL DEFAULT '0', - `title` varchar(45) DEFAULT NULL, - PRIMARY KEY (`family_id`,`character_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Family members'; - + `name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `role` tinyint(1) NOT NULL DEFAULT 0, + `title` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`family_id`, `character_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Family members' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for friends +-- ---------------------------- DROP TABLE IF EXISTS `friends`; -CREATE TABLE `friends` ( +CREATE TABLE `friends` ( `id` int NOT NULL, `friend_id` int NOT NULL, `owner` int NOT NULL, - PRIMARY KEY (`id`,`owner`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Friendslist'; - + PRIMARY KEY (`id`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Friendslist' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for housings +-- ---------------------------- DROP TABLE IF EXISTS `housings`; -CREATE TABLE `housings` ( +CREATE TABLE `housings` ( `id` int NOT NULL, - `account_id` int unsigned NOT NULL, - `owner` int unsigned NOT NULL, - `co_owner` int unsigned NOT NULL, - `template_id` int unsigned NOT NULL, - `name` varchar(128) NOT NULL, + `account_id` int UNSIGNED NOT NULL, + `owner` int UNSIGNED NOT NULL, + `co_owner` int UNSIGNED NOT NULL, + `template_id` int UNSIGNED NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `x` float NOT NULL, `y` float NOT NULL, `z` float NOT NULL, - `yaw` float NOT NULL DEFAULT '0', - `pitch` float NOT NULL DEFAULT '0', - `roll` float NOT NULL DEFAULT '0', + `yaw` float NOT NULL DEFAULT 0, + `pitch` float NOT NULL DEFAULT 0, + `roll` float NOT NULL DEFAULT 0, `current_step` tinyint NOT NULL, - `current_action` int NOT NULL DEFAULT '0', + `current_action` int NOT NULL DEFAULT 0, `permission` tinyint NOT NULL, `place_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `protected_until` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - `faction_id` int unsigned NOT NULL DEFAULT '1', - `sell_to` int unsigned NOT NULL DEFAULT '0', - `sell_price` bigint NOT NULL DEFAULT '0', - `allow_recover` tinyint unsigned NOT NULL DEFAULT '1', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player buildings'; + `faction_id` int UNSIGNED NOT NULL DEFAULT 1, + `sell_to` int UNSIGNED NOT NULL DEFAULT 0, + `sell_price` bigint NOT NULL DEFAULT 0, + `allow_recover` tinyint UNSIGNED NOT NULL DEFAULT 1, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Player buildings' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for ics_menu +-- ---------------------------- +DROP TABLE IF EXISTS `ics_menu`; +CREATE TABLE `ics_menu` ( + `id` int NOT NULL AUTO_INCREMENT, + `main_tab` tinyint UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Which main tab to display on', + `sub_tab` tinyint UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Which sub tab to display on', + `tab_pos` int NOT NULL DEFAULT 0 COMMENT 'Used to change display order', + `shop_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Id of the item group for sale (shop item)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 100 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Contains what item will be displayed on which tab' ROW_FORMAT = Dynamic; -- ---------------------------- --- Records of housings +-- Table structure for ics_shop_items -- ---------------------------- -INSERT INTO `housings` VALUES (1, 0, 0, 0, 139, 'Archeum Lodestone', 19643., 24385.4, 168.9, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (2, 0, 0, 0, 184, 'Archeum Lodestone', 19952.6, 24275.5, 140.4, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (3, 0, 0, 0, 185, 'Archeum Lodestone', 20379.4, 24126.2, 123.6, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (4, 0, 0, 0, 186, 'Archeum Lodestone', 21235.7, 23918.5, 165.0, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (5, 0, 0, 0, 187, 'Archeum Lodestone', 21441.7, 24211.7, 154.7, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (6, 0, 0, 0, 188, 'Archeum Lodestone', 22048.2, 24241.1, 154.8, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (7, 0, 0, 0, 189, 'Archeum Lodestone', 19644.0, 25077.6, 164.6, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (8, 0, 0, 0, 190, 'Archeum Lodestone', 20325.6, 25174.6, 172.9, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (9, 0, 0, 0, 191, 'Archeum Lodestone', 20890.8, 25238.5, 193.7, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (10, 0, 0, 0, 192, 'Archeum Lodestone', 21956, 24881.7, 206.3, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (11, 0, 0, 0, 271, 'Archeum Lodestone', 23060.8, 25148.3, 142.0, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); -INSERT INTO `housings` VALUES (12, 0, 0, 0, 272, 'Archeum Lodestone', 21800.3, 26893.9, 137.7, 0, 0, 0, 0, 0, 0, '0001-01-01 00:00:00', '2043-03-03 00:00:00', 2, 0, 0, 0); +DROP TABLE IF EXISTS `ics_shop_items`; +CREATE TABLE `ics_shop_items` ( + `shop_id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'SKU item id', + `display_item_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Item who\'s icon to use for displaying in the shop, leave 0 for first item in the group', + `name` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT 'Can be used to override the name in the shop', + `limited_type` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Enables limited stock mode if non-zero, Account(1), Chracter(2)', + `limited_stock_max` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Number of items left in stock for this SKU if limited stock is enabled', + `level_min` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Minimum level to buy the item (does not show on UI)', + `level_max` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Maximum level to buy the item (does not show on UI)', + `buy_restrict_type` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Buy restriction rule, none (0), level (1) or quest(2)', + `buy_restrict_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Level or QuestId for restrict rule', + `is_sale` tinyint UNSIGNED NOT NULL DEFAULT 0, + `is_hidden` tinyint UNSIGNED NOT NULL DEFAULT 0, + `sale_start` datetime NULL DEFAULT NULL COMMENT 'Limited sale start time', + `sale_end` datetime NULL DEFAULT NULL COMMENT 'Limited sale end time', + `shop_buttons` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'All (0), NoCart (1), NoGift (2), OnlyBuy (3)', + `remaining` int NOT NULL DEFAULT -1 COMMENT 'Number of items remaining, only for tab 1-1 (limited)', + PRIMARY KEY (`shop_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2000000 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Possible Item listings that are for sale' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for ics_skus +-- ---------------------------- +DROP TABLE IF EXISTS `ics_skus`; +CREATE TABLE `ics_skus` ( + `sku` int UNSIGNED NOT NULL AUTO_INCREMENT, + `shop_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Reference to the shop item', + `position` int NOT NULL DEFAULT 0 COMMENT 'Used for display order inside the item details', + `item_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Item that is for sale', + `item_count` int UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Number of items for this detail', + `select_type` tinyint UNSIGNED NOT NULL DEFAULT 0, + `is_default` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Is this the default selection?', + `event_type` tinyint UNSIGNED NOT NULL DEFAULT 0, + `event_end_date` datetime NULL DEFAULT NULL, + `currency` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Credits(0), AAPoints(1), Loyalty(2), Coins(3)', + `price` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Price of the item', + `discount_price` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Discounted price (this is used if set)', + `bonus_item_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Bonus item included for this purchase', + `bonus_item_count` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Amount of bonus items included', + `pay_item_type` int UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (`sku`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1000000 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Has the actual sales items for the details' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for item_containers +-- ---------------------------- +DROP TABLE IF EXISTS `item_containers`; +CREATE TABLE `item_containers` ( + `container_id` int UNSIGNED NOT NULL, + `container_type` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'ItemContainer' COMMENT 'Partial Container Class Name', + `slot_type` int NOT NULL DEFAULT 0 COMMENT 'Internal Container Type', + `container_size` int NOT NULL DEFAULT 50 COMMENT 'Maximum Container Size', + `owner_id` int UNSIGNED NOT NULL COMMENT 'Owning Character Id', + `mate_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Owning Mate Id', + PRIMARY KEY (`container_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for items +-- ---------------------------- DROP TABLE IF EXISTS `items`; -CREATE TABLE `items` ( - `id` bigint unsigned NOT NULL, - `type` varchar(100) NOT NULL, - `template_id` int unsigned NOT NULL, - `container_id` int unsigned NOT NULL DEFAULT '0', - `slot_type` ENUM('Equipment','Inventory','Bank','Trade','Mail','System','EquipmentMate','EquipmentSlave') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'Internal Container Type', +CREATE TABLE `items` ( + `id` bigint UNSIGNED NOT NULL, + `type` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `template_id` int UNSIGNED NOT NULL, + `container_id` int UNSIGNED NOT NULL DEFAULT 0, + `slot_type` int NOT NULL DEFAULT 0 COMMENT 'Internal Container Type', `slot` int NOT NULL, `count` int NOT NULL, - `details` blob, + `details` blob NULL, `lifespan_mins` int NOT NULL, - `made_unit_id` int unsigned NOT NULL DEFAULT '0', + `made_unit_id` int UNSIGNED NOT NULL DEFAULT 0, `unsecure_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `unpack_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', - `owner` int unsigned NOT NULL, - `grade` tinyint(1) DEFAULT '0', - `flags` tinyint unsigned NOT NULL, + `owner` int UNSIGNED NOT NULL, + `grade` tinyint(1) NULL DEFAULT 0, + `flags` tinyint UNSIGNED NOT NULL, `created_at` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', - `ucc` int unsigned NOT NULL DEFAULT '0', - `expire_time` DATETIME NULL DEFAULT NULL COMMENT 'Fixed time expire', - `expire_online_minutes` DOUBLE NOT NULL DEFAULT '0' COMMENT 'Time left when player online', - `charge_time` DATETIME NULL DEFAULT NULL COMMENT 'Time charged items got activated', - `charge_count` INT NOT NULL DEFAULT '0' COMMENT 'Number of charges left', + `ucc` int UNSIGNED NOT NULL DEFAULT 0, + `expire_time` datetime NULL DEFAULT NULL COMMENT 'Fixed time expire', + `expire_online_minutes` double NOT NULL DEFAULT 0 COMMENT 'Time left when player online', + `charge_time` datetime NULL DEFAULT NULL COMMENT 'Time charged items got activated', + `charge_count` int NOT NULL DEFAULT 0 COMMENT 'Number of charges left', PRIMARY KEY (`id`) USING BTREE, - KEY `owner` (`owner`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='All items'; - + INDEX `owner`(`owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'All items' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for mails +-- ---------------------------- DROP TABLE IF EXISTS `mails`; -CREATE TABLE `mails` ( +CREATE TABLE `mails` ( `id` int NOT NULL, `type` int NOT NULL, `status` int NOT NULL, - `title` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `text` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `sender_id` int NOT NULL DEFAULT '0', - `sender_name` varchar(45) NOT NULL, - `attachment_count` int NOT NULL DEFAULT '0', - `receiver_id` int NOT NULL DEFAULT '0', - `receiver_name` varchar(45) NOT NULL, + `title` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `text` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `sender_id` int NOT NULL DEFAULT 0, + `sender_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `attachment_count` int NOT NULL DEFAULT 0, + `receiver_id` int NOT NULL DEFAULT 0, + `receiver_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `open_date` datetime NOT NULL, `send_date` datetime NOT NULL, `received_date` datetime NOT NULL, @@ -413,248 +554,115 @@ CREATE TABLE `mails` ( `money_amount_1` int NOT NULL, `money_amount_2` int NOT NULL, `money_amount_3` int NOT NULL, - `attachment0` bigint NOT NULL DEFAULT '0', - `attachment1` bigint NOT NULL DEFAULT '0', - `attachment2` bigint NOT NULL DEFAULT '0', - `attachment3` bigint NOT NULL DEFAULT '0', - `attachment4` bigint NOT NULL DEFAULT '0', - `attachment5` bigint NOT NULL DEFAULT '0', - `attachment6` bigint NOT NULL DEFAULT '0', - `attachment7` bigint NOT NULL DEFAULT '0', - `attachment8` bigint NOT NULL DEFAULT '0', - `attachment9` bigint NOT NULL DEFAULT '0', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='In-game mails'; - + `attachment0` bigint NOT NULL DEFAULT 0, + `attachment1` bigint NOT NULL DEFAULT 0, + `attachment2` bigint NOT NULL DEFAULT 0, + `attachment3` bigint NOT NULL DEFAULT 0, + `attachment4` bigint NOT NULL DEFAULT 0, + `attachment5` bigint NOT NULL DEFAULT 0, + `attachment6` bigint NOT NULL DEFAULT 0, + `attachment7` bigint NOT NULL DEFAULT 0, + `attachment8` bigint NOT NULL DEFAULT 0, + `attachment9` bigint NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'In-game mails' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for mates +-- ---------------------------- DROP TABLE IF EXISTS `mates`; -CREATE TABLE `mates` ( - `id` int unsigned NOT NULL, - `item_id` bigint unsigned NOT NULL, - `name` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, +CREATE TABLE `mates` ( + `id` int UNSIGNED NOT NULL, + `item_id` bigint UNSIGNED NOT NULL, + `name` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `xp` int NOT NULL, `level` tinyint NOT NULL, `mileage` int NOT NULL, `hp` int NOT NULL, `mp` int NOT NULL, - `owner` int unsigned NOT NULL, + `owner` int UNSIGNED NOT NULL, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`,`item_id`,`owner`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player mounts and pets'; + PRIMARY KEY (`id`, `item_id`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Player mounts and pets' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for music +-- ---------------------------- +DROP TABLE IF EXISTS `music`; +CREATE TABLE `music` ( + `id` int NOT NULL AUTO_INCREMENT, + `author` int NOT NULL COMMENT 'PlayerId', + `title` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `song` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT 'Song MML', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'User Created Content (music)' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for options +-- ---------------------------- DROP TABLE IF EXISTS `options`; -CREATE TABLE `options` ( - `key` varchar(100) NOT NULL, - `value` text NOT NULL, - `owner` int unsigned NOT NULL, - PRIMARY KEY (`key`,`owner`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Settings that the client stores on the server'; - +CREATE TABLE `options` ( + `key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `value` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `owner` int UNSIGNED NOT NULL, + PRIMARY KEY (`key`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Settings that the client stores on the server' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for portal_book_coords +-- ---------------------------- DROP TABLE IF EXISTS `portal_book_coords`; -CREATE TABLE `portal_book_coords` ( +CREATE TABLE `portal_book_coords` ( `id` int NOT NULL, - `name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `x` int DEFAULT '0', - `y` int DEFAULT '0', - `z` int DEFAULT '0', - `zone_id` int DEFAULT '0', - `z_rot` int DEFAULT '0', - `sub_zone_id` int DEFAULT '0', + `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `x` int NULL DEFAULT 0, + `y` int NULL DEFAULT 0, + `z` int NULL DEFAULT 0, + `zone_id` int NULL DEFAULT 0, + `z_rot` int NULL DEFAULT 0, + `sub_zone_id` int NULL DEFAULT 0, `owner` int NOT NULL, - PRIMARY KEY (`id`,`owner`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Recorded house portals in the portal book'; - + PRIMARY KEY (`id`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Recorded house portals in the portal book' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for portal_visited_district +-- ---------------------------- DROP TABLE IF EXISTS `portal_visited_district`; -CREATE TABLE `portal_visited_district` ( +CREATE TABLE `portal_visited_district` ( `id` int NOT NULL, `subzone` int NOT NULL, `owner` int NOT NULL, - PRIMARY KEY (`id`,`subzone`,`owner`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='List of visited area for the portal book'; - + PRIMARY KEY (`id`, `subzone`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'List of visited area for the portal book' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for quests +-- ---------------------------- DROP TABLE IF EXISTS `quests`; -CREATE TABLE `quests` ( - `id` int unsigned NOT NULL, - `template_id` int unsigned NOT NULL, +CREATE TABLE `quests` ( + `id` int UNSIGNED NOT NULL, + `template_id` int UNSIGNED NOT NULL, `data` tinyblob NOT NULL, `status` tinyint NOT NULL, - `owner` int unsigned NOT NULL, - PRIMARY KEY (`id`,`owner`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Currently open quests'; - - -DROP TABLE IF EXISTS `skills`; -CREATE TABLE `skills` ( - `id` int unsigned NOT NULL, - `level` tinyint NOT NULL, - `type` enum('Skill','Buff') NOT NULL, - `owner` int unsigned NOT NULL, - PRIMARY KEY (`id`,`owner`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Learned character skills'; - - -DROP TABLE IF EXISTS `uccs`; -CREATE TABLE `uccs` ( - `id` int NOT NULL AUTO_INCREMENT, - `uploader_id` int NOT NULL COMMENT 'PlayerID', - `type` tinyint NOT NULL, - `data` mediumblob COMMENT 'Raw uploaded UCC data', - `pattern1` int unsigned NOT NULL COMMENT 'Background pattern', - `pattern2` int unsigned NOT NULL COMMENT 'Crest', - `color1R` int unsigned NOT NULL, - `color1G` int unsigned NOT NULL, - `color1B` int unsigned NOT NULL, - `color2R` int unsigned NOT NULL, - `color2G` int unsigned NOT NULL, - `color2B` int unsigned NOT NULL, - `color3R` int unsigned NOT NULL, - `color3G` int unsigned NOT NULL, - `color3B` int unsigned NOT NULL, - `modified` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='User Created Content (crests)'; - - -DROP TABLE IF EXISTS `music`; -CREATE TABLE `music` ( - `id` int NOT NULL AUTO_INCREMENT, - `author` int NOT NULL COMMENT 'PlayerId', - `title` varchar(128) NOT NULL, - `song` text NOT NULL COMMENT 'Song MML', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='User Created Content (music)'; - - -DROP TABLE IF EXISTS `item_containers`; -CREATE TABLE `item_containers` ( - `container_id` int unsigned NOT NULL, - `container_type` varchar(64) COLLATE 'utf8_general_ci' NOT NULL DEFAULT 'ItemContainer' COMMENT 'Partial Container Class Name', - `slot_type` enum('Equipment','Inventory','Bank','Trade','Mail','System','EquipmentMate','EquipmentSlave') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'Internal Container Type', - `container_size` int NOT NULL DEFAULT '50' COMMENT 'Maximum Container Size', - `owner_id` int unsigned NOT NULL COMMENT 'Owning Character Id', - `mate_id` INT UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Owning Mate Id', - PRIMARY KEY (`container_id`) -) COLLATE 'utf8_general_ci'; - - -DROP TABLE IF EXISTS `slaves`; -CREATE TABLE `slaves` ( - `id` INT(10) UNSIGNED NOT NULL, - `item_id` INT(10) UNSIGNED NULL DEFAULT NULL COMMENT 'Item that is used to summon this vehicle', - `template_id` INT(10) UNSIGNED NULL DEFAULT NULL COMMENT 'Slave template Id of this vehicle', - `attach_point` INT(10) NULL DEFAULT NULL COMMENT 'Binding point Id', - `name` TEXT NULL DEFAULT NULL COLLATE 'utf8_general_ci', - `owner_type` INT(10) UNSIGNED NULL DEFAULT '0' COMMENT 'Parent unit type', - `owner_id` INT(10) UNSIGNED NULL DEFAULT '0' COMMENT 'Parent unit DB Id', - `summoner` INT(10) UNSIGNED NULL DEFAULT NULL COMMENT 'Owning player', - `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP, - `hp` INT(11) NULL DEFAULT NULL, - `mp` INT(11) NULL DEFAULT NULL, - `x` FLOAT NULL DEFAULT NULL, - `y` FLOAT NULL DEFAULT NULL, - `z` FLOAT NULL DEFAULT NULL, - PRIMARY KEY (`id`) USING BTREE -) COMMENT='Player vehicles summons' COLLATE 'utf8_general_ci' ENGINE=InnoDB; - - -DROP TABLE IF EXISTS `ics_skus`; -CREATE TABLE `ics_skus` ( - `sku` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, - `shop_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Reference to the shop item', - `position` INT(10) NOT NULL DEFAULT '0' COMMENT 'Used for display order inside the item details', - `item_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Item that is for sale', - `item_count` INT(10) UNSIGNED NOT NULL DEFAULT '1' COMMENT 'Number of items for this detail', - `select_type` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', - `is_default` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Is this the default selection?', - `event_type` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', - `event_end_date` DATETIME NULL DEFAULT NULL, - `currency` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Credits(0), AAPoints(1), Loyalty(2), Coins(3)', - `price` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Price of the item', - `discount_price` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Discounted price (this is used if set)', - `bonus_item_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Bonus item included for this purchase', - `bonus_item_count` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Amount of bonus items included', - `pay_item_type` INT(10) UNSIGNED NOT NULL DEFAULT '0', - PRIMARY KEY (`sku`) USING BTREE -) -COMMENT='Has the actual sales items for the details' -COLLATE='utf8_general_ci' -ENGINE=InnoDB -AUTO_INCREMENT=1000000 -; - - -DROP TABLE IF EXISTS `ics_shop_items`; -CREATE TABLE `ics_shop_items` ( - `shop_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'SKU item id', - `display_item_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Item who\'s icon to use for displaying in the shop, leave 0 for first item in the group', - `name` TEXT NULL DEFAULT NULL COMMENT 'Can be used to override the name in the shop' COLLATE 'utf8_general_ci', - `limited_type` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Enables limited stock mode if non-zero, Account(1), Chracter(2)', - `limited_stock_max` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Number of items left in stock for this SKU if limited stock is enabled', - `level_min` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Minimum level to buy the item (does not show on UI)', - `level_max` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Maximum level to buy the item (does not show on UI)', - `buy_restrict_type` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Buy restriction rule, none (0), level (1) or quest(2)', - `buy_restrict_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Level or QuestId for restrict rule', - `is_sale` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', - `is_hidden` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', - `sale_start` DATETIME NULL DEFAULT NULL COMMENT 'Limited sale start time', - `sale_end` DATETIME NULL DEFAULT NULL COMMENT 'Limited sale end time', - `shop_buttons` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'All (0), NoCart (1), NoGift (2), OnlyBuy (3)', - `remaining` INT(11) NOT NULL DEFAULT '-1' COMMENT 'Number of items remaining, only for tab 1-1 (limited)', - PRIMARY KEY (`shop_id`) USING BTREE -) -COMMENT='Possible Item listings that are for sale' -COLLATE='utf8_general_ci' -ENGINE=InnoDB -AUTO_INCREMENT=2000000 -; - - -DROP TABLE IF EXISTS `ics_menu`; -CREATE TABLE `ics_menu` ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `main_tab` TINYINT(3) UNSIGNED NOT NULL DEFAULT '1' COMMENT 'Which main tab to display on', - `sub_tab` TINYINT(3) UNSIGNED NOT NULL DEFAULT '1' COMMENT 'Which sub tab to display on', - `tab_pos` INT(11) NOT NULL DEFAULT '0' COMMENT 'Used to change display order', - `shop_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Id of the item group for sale (shop item)', - PRIMARY KEY (`id`) USING BTREE -) -COMMENT='Contains what item will be displayed on which tab' -COLLATE='utf8_general_ci' -ENGINE=InnoDB -AUTO_INCREMENT=100 -; - - -DROP TABLE IF EXISTS `audit_ics_sales`; -CREATE TABLE `audit_ics_sales` ( - `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, - `buyer_account` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Account ID of the person buying this item', - `buyer_char` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Character that was logged in when buying', - `target_account` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Account of the person receiving the goods', - `target_char` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Character that received the goods', - `sale_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Time of purchase (in UTC)', - `shop_item_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Shop item entry id of the sold item', - `sku` INT(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'SKU of the sold item', - `sale_cost` INT(11) NOT NULL DEFAULT '0' COMMENT 'Amount this item was sold for', - `sale_currency` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Which currency was used', - `description` TEXT NOT NULL COMMENT 'Added description of this transaction' COLLATE 'utf8_general_ci', - PRIMARY KEY (`id`) USING BTREE, - INDEX `buyer_account` (`buyer_account`) USING BTREE, - INDEX `buyer_char` (`buyer_char`) USING BTREE, - INDEX `target_account` (`target_account`) USING BTREE, - INDEX `target_char` (`target_char`) USING BTREE -) -COMMENT='Sales history for the ICS' -COLLATE='utf8_general_ci' -ENGINE=InnoDB -; + `owner` int UNSIGNED NOT NULL, + PRIMARY KEY (`id`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Currently open quests' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for resident_members +-- ---------------------------- +DROP TABLE IF EXISTS `resident_members`; +CREATE TABLE `resident_members` ( + `id` int NOT NULL, + `resident_id` int NOT NULL, + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `level` tinyint(1) NOT NULL, + `family` int NULL DEFAULT NULL, + `service_point` int NULL DEFAULT NULL, + PRIMARY KEY (`id`, `resident_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for residents @@ -669,29 +677,78 @@ CREATE TABLE `residents` ( `zone_point` int NULL DEFAULT NULL, `charge` datetime NOT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 30 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC; +-- ---------------------------- +-- Table structure for skills +-- ---------------------------- +DROP TABLE IF EXISTS `skills`; +CREATE TABLE `skills` ( + `id` int UNSIGNED NOT NULL, + `level` tinyint NOT NULL, + `type` enum('Skill','Buff') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `owner` int UNSIGNED NOT NULL, + PRIMARY KEY (`id`, `owner`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Learned character skills' ROW_FORMAT = Dynamic; -- ---------------------------- --- Table structure for resident_members +-- Table structure for slaves -- ---------------------------- -DROP TABLE IF EXISTS `resident_members`; -CREATE TABLE `resident_members` ( - `id` int NOT NULL, - `resident_id` int NOT NULL, - `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `level` tinyint(1) NOT NULL, - `family` int NULL DEFAULT NULL, - `service_point` int NULL DEFAULT NULL, - PRIMARY KEY (`id`, `resident_id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; +DROP TABLE IF EXISTS `slaves`; +CREATE TABLE `slaves` ( + `id` int UNSIGNED NOT NULL, + `item_id` int UNSIGNED NULL DEFAULT NULL COMMENT 'Item that is used to summon this vehicle', + `template_id` int UNSIGNED NULL DEFAULT NULL COMMENT 'Slave template Id of this vehicle', + `attach_point` int NULL DEFAULT NULL COMMENT 'Binding point Id', + `name` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL, + `owner_type` int UNSIGNED NULL DEFAULT 0 COMMENT 'Parent unit type', + `owner_id` int UNSIGNED NULL DEFAULT 0 COMMENT 'Parent unit DB Id', + `summoner` int UNSIGNED NULL DEFAULT NULL COMMENT 'Owning player', + `created_at` datetime NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NULL DEFAULT CURRENT_TIMESTAMP, + `hp` int NULL DEFAULT NULL, + `mp` int NULL DEFAULT NULL, + `x` float NULL DEFAULT NULL, + `y` float NULL DEFAULT NULL, + `z` float NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Player vehicles summons' ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for uccs +-- ---------------------------- +DROP TABLE IF EXISTS `uccs`; +CREATE TABLE `uccs` ( + `id` int NOT NULL AUTO_INCREMENT, + `uploader_id` int NOT NULL COMMENT 'PlayerID', + `type` tinyint NOT NULL, + `data` mediumblob NULL COMMENT 'Raw uploaded UCC data', + `pattern1` int UNSIGNED NOT NULL COMMENT 'Background pattern', + `pattern2` int UNSIGNED NOT NULL COMMENT 'Crest', + `color1R` int UNSIGNED NOT NULL, + `color1G` int UNSIGNED NOT NULL, + `color1B` int UNSIGNED NOT NULL, + `color2R` int UNSIGNED NOT NULL, + `color2G` int UNSIGNED NOT NULL, + `color2B` int UNSIGNED NOT NULL, + `color3R` int UNSIGNED NOT NULL, + `color3G` int UNSIGNED NOT NULL, + `color3B` int UNSIGNED NOT NULL, + `modified` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'User Created Content (crests)' ROW_FORMAT = Dynamic; -DROP TABLE IF EXISTS `attendances`; -CREATE TABLE `attendances` ( - `id` tinyint unsigned NOT NULL, - `owner` BIGINT UNSIGNED NOT NULL, - `account_attendance` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', - `accept` tinyint(1) NOT NULL, - PRIMARY KEY (`id`,`owner`) USING BTREE +-- ---------------------------- +-- Table structure for divine_clock +-- ---------------------------- +DROP TABLE IF EXISTS `divine_clock`; +CREATE TABLE `divine_clock` ( + `id` int NOT NULL AUTO_INCREMENT, + `account_id` bigint UNSIGNED NOT NULL, + `schedule_item_id` INT UNSIGNED NOT NULL COMMENT 'This field corresponds to the id field in the schedule_items table', + `gave` tinyint NOT NULL DEFAULT 0 COMMENT 'Number of clicks taken today', + `cumulated` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Time that has been passed already', + PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/SQL/patches/compact_server_table/loots_5070_add_memory-ember.sql b/SQL/patches/compact_server_table/loots_5070_add_memory-ember.sql new file mode 100644 index 0000000000..13873fb46f --- /dev/null +++ b/SQL/patches/compact_server_table/loots_5070_add_memory-ember.sql @@ -0,0 +1,15 @@ +-- Author: Black Judge - 2024/09/12 +-- Исправляем ошибку: В камине нельзя взять уголёк Id=36917 "Memory Ember" +-- Отсутствуют записи о луте для версий больше 1.2. +-- Fixing a bug: You cannot take ember from the fireplace Id=36917 "Memory Ember" +-- There are no records of loot for versions greater than 1.2. + +-- ---------------------------- +-- Records of loots +-- ---------------------------- +INSERT INTO "loots" VALUES (80462, 1, 36917, 10000000, 1, 1, 9972, 0, 'f'); + +-- ---------------------------- +-- Records of loot_groups +-- ---------------------------- +INSERT INTO "loot_groups" VALUES (2051, 9972, 1, 10000000, 0); diff --git a/SQL/updates/2024-06-09_aaemu_game_divine_clock.sql b/SQL/updates/2024-06-09_aaemu_game_divine_clock.sql new file mode 100644 index 0000000000..23ce2b0b96 --- /dev/null +++ b/SQL/updates/2024-06-09_aaemu_game_divine_clock.sql @@ -0,0 +1,23 @@ +-- ---------------------------- +-- Table structure for divine_clock +-- ---------------------------- +DROP TABLE IF EXISTS `divine_clock`; +CREATE TABLE `divine_clock` ( + `id` int NOT NULL AUTO_INCREMENT, + `account_id` bigint UNSIGNED NOT NULL, + `schedule_item_id` INT UNSIGNED NOT NULL COMMENT 'This field corresponds to the id field in the schedule_items table', + `gave` tinyint NOT NULL DEFAULT 0 COMMENT 'Number of clicks taken today', + `cumulated` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Time that has been passed already', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci; + +-- ---------------------------- +-- Table structure for accounts +-- ---------------------------- +-- Удаление поля divine_clock_time +ALTER TABLE `accounts` +DROP COLUMN `divine_clock_time`; + +-- Удаление поля divine_clock_taken +ALTER TABLE `accounts` +DROP COLUMN `divine_clock_taken`; \ No newline at end of file diff --git a/SQL/updates/2024-09-16_aaemu_game_item_containers_update.sql b/SQL/updates/2024-09-16_aaemu_game_item_containers_update.sql new file mode 100644 index 0000000000..dbe6e7caf1 --- /dev/null +++ b/SQL/updates/2024-09-16_aaemu_game_item_containers_update.sql @@ -0,0 +1,8 @@ +-- -------------------------------------------- +-- Update item_containers table with +-- -------------------------------------------- +ALTER TABLE item_containers + DROP COLUMN slot_type; +ALTER TABLE item_containers + ADD COLUMN `slot_type` INT(11) NOT NULL DEFAULT '0' COMMENT 'Internal Container Type' AFTER `container_type`; + \ No newline at end of file diff --git a/SQL/updates/2024-09-16_aaemu_game_items_update.sql b/SQL/updates/2024-09-16_aaemu_game_items_update.sql new file mode 100644 index 0000000000..5c31e26cd8 --- /dev/null +++ b/SQL/updates/2024-09-16_aaemu_game_items_update.sql @@ -0,0 +1,7 @@ +-- -------------------------------------------- +-- Update items table +-- -------------------------------------------- +ALTER TABLE items + DROP COLUMN slot_type; +ALTER TABLE items + ADD COLUMN `slot_type` INT(11) NOT NULL DEFAULT '0' COMMENT 'Internal Container Type' AFTER `container_id`; diff --git a/SQL/updates/2024-10-04_aaemu_game_auction_house_update.sql b/SQL/updates/2024-10-04_aaemu_game_auction_house_update.sql new file mode 100644 index 0000000000..7e3f23784e --- /dev/null +++ b/SQL/updates/2024-10-04_aaemu_game_auction_house_update.sql @@ -0,0 +1,39 @@ +-- ---------------------------------- +-- Table structure for auction_house +-- ---------------------------------- +DROP TABLE IF EXISTS `auction_house`; +CREATE TABLE `auction_house` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `duration` tinyint NOT NULL, + `item_id` int NOT NULL, + `object_id` bigint NOT NULL, + `grade` tinyint(1) NOT NULL, + `flags` tinyint(1) NOT NULL, + `stack_size` int NOT NULL, + `detail_type` tinyint(1) NOT NULL, + `details` blob NULL, + `creation_time` datetime NOT NULL, + `end_time` datetime NOT NULL, + `lifespan_mins` int NOT NULL, + `made_unit_id` int NOT NULL, + `world_id` tinyint NOT NULL, + `unsecure_date_time` datetime NOT NULL, + `unpack_date_time` datetime NOT NULL, + `charge_use_skill_time` datetime NOT NULL, + `world_id_2` tinyint NOT NULL, + `client_id` int NOT NULL, + `client_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `start_money` int NOT NULL, + `direct_money` int NOT NULL, + `charge_percent` int NOT NULL, + `bid_world_id` tinyint(1) NOT NULL, + `bidder_id` int NOT NULL, + `bidder_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `bid_money` int NOT NULL, + `extra` int NOT NULL, + `min_stack` int NOT NULL, + `max_stack` int NOT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Listed AH Items' ROW_FORMAT = DYNAMIC; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/SQL/updates/2024-10-06_aaemu_game_auction_sold.sql b/SQL/updates/2024-10-06_aaemu_game_auction_sold.sql new file mode 100644 index 0000000000..1c4290d897 --- /dev/null +++ b/SQL/updates/2024-10-06_aaemu_game_auction_sold.sql @@ -0,0 +1,15 @@ +-- ---------------------------------- +-- Table structure for auction_sold +-- ---------------------------------- +DROP TABLE IF EXISTS `auction_sold`; +CREATE TABLE auction_sold ( + id INT AUTO_INCREMENT PRIMARY KEY, + item_id INT UNSIGNED NOT NULL, + day INT NOT NULL, + min_copper BIGINT NOT NULL, + max_copper BIGINT NOT NULL, + avg_copper BIGINT NOT NULL, + volume INT NOT NULL, + item_grade TINYINT NOT NULL, + weekly_avg_copper BIGINT NOT NULL +); \ No newline at end of file diff --git a/SQL/updates/2024-10-25_aaemu_game_auction_house_update.sql b/SQL/updates/2024-10-25_aaemu_game_auction_house_update.sql new file mode 100644 index 0000000000..7d3dc7a733 --- /dev/null +++ b/SQL/updates/2024-10-25_aaemu_game_auction_house_update.sql @@ -0,0 +1,26 @@ +-- ---------------------------------- +-- Table structure for auction_house +-- ---------------------------------- +DROP TABLE IF EXISTS `auction_house`; +CREATE TABLE `auction_house` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `duration` tinyint NOT NULL, + `item_id` bigint NOT NULL, + `end_time` datetime NOT NULL, + `world_id` tinyint NOT NULL, + `client_id` int NOT NULL, + `client_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `start_money` int NOT NULL, + `direct_money` int NOT NULL, + `charge_percent` int NOT NULL, + `bid_world_id` int NOT NULL, + `bidder_id` int NOT NULL, + `bidder_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `bid_money` int NOT NULL, + `extra` int NOT NULL, + `min_stack` int NOT NULL, + `max_stack` int NOT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Listed AH Items' ROW_FORMAT = DYNAMIC; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/SQL/updates/2024-10-28_aaemu_game_auction_solds_data_update.sql b/SQL/updates/2024-10-28_aaemu_game_auction_solds_data_update.sql new file mode 100644 index 0000000000..b098dc24d1 --- /dev/null +++ b/SQL/updates/2024-10-28_aaemu_game_auction_solds_data_update.sql @@ -0,0 +1,16 @@ +-- ---------------------------------- +-- Table structure for auction_solds_data +-- ---------------------------------- +DROP TABLE IF EXISTS `auction_sold`; +DROP TABLE IF EXISTS `auction_solds_data`; +CREATE TABLE auction_solds_data ( + item_id INT UNSIGNED NOT NULL, + item_grade TINYINT NOT NULL, + date datetime NOT NULL, + min_copper BIGINT NOT NULL, + max_copper BIGINT NOT NULL, + avg_copper BIGINT NOT NULL, + volume INT NOT NULL, + weekly_avg_copper BIGINT NOT NULL, + PRIMARY KEY (item_id, item_grade, date) +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; From df0ab26ec78ece5fae6ce89c981ef201c6ecc6c5 Mon Sep 17 00:00:00 2001 From: NLObP <38990417+NL0bP@users.noreply.github.com> Date: Sun, 23 Mar 2025 20:22:56 +0300 Subject: [PATCH 2/3] =?UTF-8?q?=D0=9E=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=BD=D0=B0=2006=20=D0=BD=D0=BE=D1=8F=D0=B1=D1=80=D1=8F=202?= =?UTF-8?q?024=20=D0=B3=D0=BE=D0=B4=D0=B0:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Game] Исправление почты: Исправлена обычная почта: - Можно забрать только деньги; - Можно забрать и деньги и предметы; - Можно забрать все вложения из выбранных писем; - Можно удалить выбранные письма; - Можно удалить все письма без вложений; - Теперь письма не удаляются после прочтения и получения предметов; Исправлена почта внутриигрового магазина: - Можно получить все предметы из всех писем; - Письмо можно открыть для получения предмета; - Теперь письма удаляются после прочтения и получения предметов; --- Main changes as of November 6, 2024: [Game] Mail fix: Regular mail fixed: - You can only take money; - You can pick up both money and items; - You can pick up all attachments from selected letters; - You can delete selected letters; - You can delete all letters without attachments; - Now letters are not deleted after reading and receiving items; Fixed in-game store mail: - You can get all items from all letters; - The letter can be opened to receive an item; - Now letters are deleted after reading and receiving items; --- AAEmu.Game/Core/Managers/AuctionManager.cs | 663 +++++++++--------- AAEmu.Game/Core/Managers/HousingManager.cs | 1 - .../Core/Managers/Id/AuctionIdManager.cs | 18 + AAEmu.Game/Core/Managers/ItemManager.cs | 4 + AAEmu.Game/Core/Managers/MailManager.cs | 38 +- .../C2G/CSChangeSlaveEquipmentPacket.cs | 10 + .../Core/Packets/C2G/CSICSBuyGoodPacket.cs | 6 +- .../C2G/CSTakeAllAttachmentItemPacket.cs | 6 +- .../C2G/CSTakeAttachmentMoneyPacket.cs | 2 +- .../C2G/CSTakeAttachmentSequentiallyPacket.cs | 38 +- AAEmu.Game/GameService.cs | 1 + AAEmu.Game/Models/Game/Char/CharacterMails.cs | 161 +++-- .../DoodadObj/Funcs/DoodadFuncLootPack.cs | 2 + .../Models/Game/Items/Actions/ItemTask.cs | 3 + .../Models/Game/Items/Actions/ItemTaskType.cs | 20 +- .../Game/Items/Containers/ItemContainer.cs | 168 +++++ AAEmu.Game/Models/Game/Mails/BaseMail.cs | 1 - .../Models/Game/Mails/CommercialMail.cs | 39 +- .../Models/Game/Mails/CountUnreadMail.cs | 11 +- AAEmu.Game/Models/Game/Mails/MailBody.cs | 1 - .../Models/Game/Mails/MailPlayerToPlayer.cs | 1 - .../Models/Game/Mails/Static/MailType.cs | 2 +- .../Skills/Effects/GainLootPackItemEffect.cs | 2 + .../Effects/SpecialEffects/FishingLoot.cs | 2 + .../Models/Tasks/CashShop/CashShopBuyTask.cs | 13 +- AAEmu.Game/Scripts/Commands/TestMails.cs | 1 - .../Services/WebApi/Models/SendMailRequest.cs | 1 - SQL/aaemu_game.sql | 147 ++-- ...-10-30_aaemu_game_auction_house_update.sql | 2 + 29 files changed, 817 insertions(+), 547 deletions(-) create mode 100644 AAEmu.Game/Core/Managers/Id/AuctionIdManager.cs create mode 100644 SQL/updates/2024-10-30_aaemu_game_auction_house_update.sql diff --git a/AAEmu.Game/Core/Managers/AuctionManager.cs b/AAEmu.Game/Core/Managers/AuctionManager.cs index 7f759fa5d0..56366aacc2 100644 --- a/AAEmu.Game/Core/Managers/AuctionManager.cs +++ b/AAEmu.Game/Core/Managers/AuctionManager.cs @@ -1,17 +1,18 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Text; -using AAEmu.Commons.Network; using AAEmu.Commons.Utils; using AAEmu.Commons.Utils.DB; +using AAEmu.Game.Core.Managers.Id; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Auction; using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; using AAEmu.Game.Models.Game.Mails; -using AAEmu.Game.Scripts.Commands; using MySql.Data.MySqlClient; @@ -23,20 +24,23 @@ public class AuctionManager : Singleton { private static Logger Logger { get; } = LogManager.GetCurrentClassLogger(); - public List AuctionLots; - public Dictionary<(uint TemplateId, byte Grade), List<(DateTime Date, AuctionLot Lot)>> SalesData = new(); - public Dictionary<(uint TemplateId, byte Grade), List<(DateTime Date, AuctionSold Sold)>> SoldsData = new(); - - public List _deletedAuctionItemIds; + public ConcurrentBag AuctionLots { get; } = []; + private ConcurrentDictionary<(uint TemplateId, byte Grade), List<(DateTime Date, AuctionLot Lot)>> SalesData { get; } = new(); + private ConcurrentDictionary<(uint TemplateId, byte Grade), List<(DateTime Date, AuctionSold Sold)>> SoldsData { get; } = new(); + internal ConcurrentBag _deletedAuctionItemIds { get; } = []; private static int MaxListingFee = 1000000; // 100g, 100 copper coins = 1 silver, 100 silver = 1 gold. private void RemoveAuctionLotSold(AuctionLot itemToRemove, string buyer, int soldAmount) { - if (AuctionLots.Contains(itemToRemove)) + if (!AuctionLots.Contains(itemToRemove)) { - var newItem = ItemManager.Instance.GetItemByItemId(itemToRemove.Item.Id); + return; + } + var newItem = ItemManager.Instance.GetItemByItemId(itemToRemove.Item.Id); + if (newItem != null) + { var itemList = new Item[10].ToList(); itemList[0] = newItem; @@ -44,7 +48,6 @@ private void RemoveAuctionLotSold(AuctionLot itemToRemove, string buyer, int sol var moneyToSend = new int[3]; moneyToSend[0] = (int)moneyAfterFee; - // TODO: Read this from saved data var recalculatedFee = itemToRemove.DirectMoney * .01 * ((int)itemToRemove.Duration - 8 + 1); if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; @@ -59,32 +62,31 @@ private void RemoveAuctionLotSold(AuctionLot itemToRemove, string buyer, int sol var buyerId = NameManager.Instance.GetCharacterId(buyer); buyMail.FinalizeForSaleBuyer(buyerId); buyMail.Send(); - - RemoveAuctionLot(itemToRemove); } + + RemoveAuctionLot(itemToRemove); } private void BuyPartOfTheAuctionLot(AuctionLot auctionLot, string buyer, int soldAmount, int count) { - // предмет должен быть с новым id + // the item must have a new id var itemTemplate = ItemManager.Instance.GetItemTemplateFromItemId(auctionLot.Item.TemplateId); var newItem = ItemManager.Instance.Create(itemTemplate.Id, count, auctionLot.Item.Grade); var moneyAfterFee = soldAmount * .9; - // TODO: Read this from saved data var recalculatedFee = auctionLot.DirectMoney * .01 * ((int)auctionLot.Duration - 8 + 1); if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; if (auctionLot.ClientName != "") { - // Хозяину отсылаем часть денег за покупку + // We send the owner a portion of the purchase money. var sellMail = new MailForAuction(newItem, auctionLot.ClientId, soldAmount, (int)recalculatedFee); sellMail.FinalizeForSaleSeller((int)moneyAfterFee, (int)(soldAmount - moneyAfterFee)); sellMail.Send(); } - // Покупателю отсылаем купленный лот + // Send the purchased item to the buyer var buyMail = new MailForAuction(newItem, auctionLot.ClientId, soldAmount, (int)recalculatedFee); var buyerId = NameManager.Instance.GetCharacterId(buyer); buyMail.FinalizeForSaleBuyer(buyerId); @@ -98,26 +100,32 @@ private void RemoveAuctionLotFail(AuctionLot itemToRemove) if (!AuctionLots.Contains(itemToRemove)) return; - if (itemToRemove.BidderName != "") // Player won the bid. + if (itemToRemove.BidderName != "") // Player won the bid { RemoveAuctionLotSold(itemToRemove, itemToRemove.BidderName, itemToRemove.BidMoney); return; } // Item did not sell by end of the timer. - var newItem = ItemManager.Instance.GetItemByItemId(itemToRemove.Item.Id); - var itemList = new Item[10].ToList(); - itemList[0] = newItem; + if (itemToRemove.Item != null) + { + var newItem = ItemManager.Instance.GetItemByItemId(itemToRemove.Item.Id); + if (newItem != null) + { + var itemList = new Item[10].ToList(); + itemList[0] = newItem; - // TODO: Read this from saved data - var recalculatedFee = itemToRemove.DirectMoney * .01 * ((int)itemToRemove.Duration - 8 + 1); - if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; + // TODO: Read this from saved data + var recalculatedFee = itemToRemove.DirectMoney * .01 * ((int)itemToRemove.Duration - 8 + 1); + if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; - if (itemToRemove.ClientName != "") - { - var failMail = new MailForAuction(newItem, itemToRemove.ClientId, itemToRemove.DirectMoney, (int)recalculatedFee); - failMail.FinalizeForFail(); - failMail.Send(); + if (itemToRemove.ClientName != "") + { + var failMail = new MailForAuction(newItem, itemToRemove.ClientId, itemToRemove.DirectMoney, (int)recalculatedFee); + failMail.FinalizeForFail(); + failMail.Send(); + } + } } RemoveAuctionLot(itemToRemove); @@ -126,21 +134,35 @@ private void RemoveAuctionLotFail(AuctionLot itemToRemove) public void CancelAuctionLot(Character player, ulong auctionId) { var auctionItem = GetAuctionLotFromId(auctionId); + if (auctionItem == null) + { + Logger.Warn($"AuctionLot with ID {auctionId} not found."); + return; + } - if (auctionItem.BidderName != "") return;// Someone has already bid on the item and we do not want to remove it. + if (auctionItem.BidderName != "") // Someone has already bid on the item and we do not want to remove it + { + Logger.Warn($"AuctionLot with ID {auctionId} has already been bid on."); + return; + } var moneyToSubtract = auctionItem.DirectMoney * .1f; var itemList = new Item[10].ToList(); - var newItem = ItemManager.Instance.Create(auctionItem.Item.TemplateId, auctionItem.Item.Count, auctionItem.Item.Grade); - itemList[0] = newItem; + //var newItem = ItemManager.Instance.Create(auctionItem.Item.TemplateId, auctionItem.Item.Count, auctionItem.Item.Grade); + var newItem = ItemManager.Instance.GetItemByItemId(auctionItem.Item.Id); + if (newItem != null) + { + itemList[0] = newItem; - // TODO: Read this from saved data - var recalculatedFee = auctionItem.DirectMoney * .01 * ((int)auctionItem.Duration - 8 + 1); - if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; + // TODO: Read this from saved data + var recalculatedFee = auctionItem.DirectMoney * .01 * ((int)auctionItem.Duration - 8 + 1); + if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; + + var cancelMail = new MailForAuction(newItem, auctionItem.ClientId, auctionItem.DirectMoney, (int)recalculatedFee); + cancelMail.FinalizeForCancel(); + cancelMail.Send(); + } - var cancelMail = new MailForAuction(newItem, auctionItem.ClientId, auctionItem.DirectMoney, (int)recalculatedFee); - cancelMail.FinalizeForCancel(); - cancelMail.Send(); //MailManager.Instance.SendMail(0, auctionItem.ClientName, "AuctionHouse", "Cancelled Listing", "See attached.", 1, new int[3], 0, itemList); RemoveAuctionLot(auctionItem); @@ -149,140 +171,127 @@ public void CancelAuctionLot(Character player, ulong auctionId) private AuctionLot GetAuctionLotFromId(ulong auctionId) { - var lot = AuctionLots.Single(c => c.Id == auctionId); - - return lot; + return AuctionLots.SingleOrDefault(lot => lot.Id == auctionId); } public void BidOnAuctionLot(Character player, uint auctioneerId, uint auctioneerId2, AuctionLot lot, AuctionBid bid) { if (player == null || lot == null || bid == null) { - // Логирование или обработка ошибки Logger.Warn("Invalid arguments passed to BidOnAuctionLot."); return; } - //var auctionItem = GetAuctionLotFromId(lot.Id); - var auctionLot = lot; - if (auctionLot != null) + var auctionLot = GetAuctionLotFromId(lot.Id); + if (auctionLot == null) { - // TODO сравним, что прислал клиент и что есть на сервере - // auctionItem == lot ? + Logger.Warn("Invalid auctionItem passed to BidOnAuctionLot."); + Logger.Warn($"AuctionLot with ID {lot.Id} not found in the list."); + return; + } - if (bid.StackSize != 0 && bid.StackSize >= auctionLot.MinStack && bid.StackSize <= auctionLot.MaxStack && auctionLot.BidderId == 0) // Buy part of the lot - { - BuyPartOfTheAuctionLot(auctionLot, player.Name, bid.Money, bid.StackSize); + if (bid.StackSize != 0 && bid.StackSize >= auctionLot.MinStack && bid.StackSize <= auctionLot.MaxStack && auctionLot.BidderId == 0) + { + BuyPartOfTheAuctionLot(auctionLot, player.Name, bid.Money, bid.StackSize); - // Set info to new bidders info - auctionLot.Item.Count -= bid.StackSize; + auctionLot.Item.Count -= bid.StackSize; - bid.BidderName = player.Name; - bid.BidderId = player.Id; - bid.WorldId = (byte)player.Transform.WorldId; + bid.BidderName = player.Name; + bid.BidderId = player.Id; + bid.WorldId = (byte)player.Transform.WorldId; - player.SubtractMoney(SlotType.Bag, bid.Money); - player.SendPacket(new SCAuctionBidPacket(bid, false, auctionLot.Item.TemplateId)); - auctionLot.IsDirty = true; + player.SubtractMoney(SlotType.Bag, bid.Money); + player.SendPacket(new SCAuctionBidPacket(bid, false, auctionLot.Item.TemplateId)); + auctionLot.IsDirty = true; - // Обновление данных в списке AuctionLots - UpdateAuctionLotInList(auctionLot); + UpdateAuctionLotInList(auctionLot); - auctionLot.BidMoney = bid.Money; - auctionLot.Extra = bid.StackSize; - } - else if (bid.Money >= auctionLot.DirectMoney && auctionLot.DirectMoney != 0) // Buy now + auctionLot.BidMoney = bid.Money; + auctionLot.Extra = bid.StackSize; + } + else if (bid.Money >= auctionLot.DirectMoney && auctionLot.DirectMoney != 0) // Buy now + { + if (auctionLot.BidderId != 0) // send mail to person who bid if item was bought at full price. { - if (auctionLot.BidderId != 0) // send mail to person who bid if item was bought at full price. - { - var newMail = new MailForAuction(auctionLot.Item.TemplateId, auctionLot.ClientId, auctionLot.DirectMoney, 0); - newMail.FinalizeForBidFail(auctionLot.BidderId, auctionLot.BidMoney); - newMail.Send(); - } + var newMail = new MailForAuction(auctionLot.Item.TemplateId, auctionLot.ClientId, auctionLot.DirectMoney, 0); + newMail.FinalizeForBidFail(auctionLot.BidderId, auctionLot.BidMoney); + newMail.Send(); + } - player.SubtractMoney(SlotType.Bag, auctionLot.DirectMoney); - RemoveAuctionLotSold(auctionLot, player.Name, auctionLot.DirectMoney); + player.SubtractMoney(SlotType.Bag, auctionLot.DirectMoney); + RemoveAuctionLotSold(auctionLot, player.Name, auctionLot.DirectMoney); - auctionLot.BidMoney = bid.Money; - auctionLot.Extra = bid.StackSize; - } - else if (bid.Money > auctionLot.BidMoney) // Bid + auctionLot.BidMoney = bid.Money; + auctionLot.Extra = bid.StackSize; + } + else if (bid.Money > auctionLot.BidMoney) // Bid + { + if (auctionLot.BidderName != "" && auctionLot.BidderId != 0) // Send mail to old bidder. { - if (auctionLot.BidderName != "" && auctionLot.BidderId != 0) // Send mail to old bidder. - { - var moneyArray = new int[3]; - moneyArray[0] = auctionLot.BidMoney; + var moneyArray = new int[3]; + moneyArray[0] = auctionLot.BidMoney; - // TODO: Read this from saved data - var recalculatedFee = auctionLot.DirectMoney * .01 * ((int)auctionLot.Duration - 8 + 1); - if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; + // TODO: Read this from saved data + var recalculatedFee = auctionLot.DirectMoney * .01 * ((int)auctionLot.Duration - 8 + 1); + if (recalculatedFee > MaxListingFee) recalculatedFee = MaxListingFee; - var cancelMail = new MailForAuction(auctionLot.Item.TemplateId, auctionLot.ClientId, auctionLot.DirectMoney, (int)recalculatedFee); - cancelMail.FinalizeForBidFail(auctionLot.BidderId, auctionLot.BidMoney); - cancelMail.Send(); - } + var cancelMail = new MailForAuction(auctionLot.Item.TemplateId, auctionLot.ClientId, auctionLot.DirectMoney, (int)recalculatedFee); + cancelMail.FinalizeForBidFail(auctionLot.BidderId, auctionLot.BidMoney); + cancelMail.Send(); + } - // Set info to new bidders info - auctionLot.BidderName = player.Name; - auctionLot.BidderId = player.Id; - auctionLot.BidWorldId = (byte)player.Transform.WorldId; - auctionLot.BidMoney = bid.Money; + // Set info to new bidders info + auctionLot.BidderName = player.Name; + auctionLot.BidderId = player.Id; + auctionLot.BidWorldId = (byte)player.Transform.WorldId; + auctionLot.BidMoney = bid.Money; - bid.BidderName = player.Name; - bid.BidderId = player.Id; - bid.WorldId = (byte)player.Transform.WorldId; + bid.BidderName = player.Name; + bid.BidderId = player.Id; + bid.WorldId = (byte)player.Transform.WorldId; - player.SubtractMoney(SlotType.Bag, bid.Money, ItemTaskType.Auction); - player.SendPacket(new SCAuctionBidPacket(bid, false, auctionLot.Item.TemplateId)); - auctionLot.IsDirty = true; + player.SubtractMoney(SlotType.Bag, bid.Money, ItemTaskType.Auction); + player.SendPacket(new SCAuctionBidPacket(bid, false, auctionLot.Item.TemplateId)); + auctionLot.IsDirty = true; - // Обновление данных в списке AuctionLots - UpdateAuctionLotInList(auctionLot); + // Обновление данных в списке AuctionLots + UpdateAuctionLotInList(auctionLot); - auctionLot.BidMoney = bid.Money; - auctionLot.Extra = bid.StackSize; - } - - AddAuctionSold(auctionLot); + auctionLot.BidMoney = bid.Money; + auctionLot.Extra = bid.StackSize; } + + AddAuctionSold(auctionLot); } - public void UpdateAuctionLotInList(AuctionLot auctionLot) + private void UpdateAuctionLotInList(AuctionLot auctionLot) { if (auctionLot == null) { - // Логирование или обработка ошибки Logger.Warn("Invalid auctionItem passed to UpdateAuctionLotInList."); return; } - lock (AuctionLots) + var existingLot = AuctionLots.FirstOrDefault(lot => lot.Id == auctionLot.Id); + if (existingLot != null) { - // Поиск лота в списке по идентификатору - var existingLot = AuctionLots.FirstOrDefault(lot => lot.Id == auctionLot.Id); - - if (existingLot != null) - { - // Обновление данных лота - existingLot.BidderName = auctionLot.BidderName; - existingLot.BidderId = auctionLot.BidderId; - existingLot.BidWorldId = auctionLot.BidWorldId; - existingLot.BidMoney = auctionLot.BidMoney; - existingLot.Item.Count = auctionLot.Item.Count; - existingLot.IsDirty = auctionLot.IsDirty; - } - else - { - // Логирование или обработка ошибки, если лот не найден - Logger.Warn($"AuctionLot with ID {auctionLot.Id} not found in the list."); - } + // Обновление данных лота + existingLot.BidderName = auctionLot.BidderName; + existingLot.BidderId = auctionLot.BidderId; + existingLot.BidWorldId = auctionLot.BidWorldId; + existingLot.BidMoney = auctionLot.BidMoney; + existingLot.Item = auctionLot.Item; + existingLot.IsDirty = auctionLot.IsDirty; + } + else + { + Logger.Warn($"AuctionLot with ID {auctionLot.Id} not found in the list."); } } public void GetBidAuctionLots(Character player, int page) { var searchedArticles = AuctionLots.Where(lot => lot.BidderId == player.Id).ToList(); - if (searchedArticles.Count <= 0) { player.SendPacket(new SCAuctionSearchedPacket(0, 0, [], (short)ErrorMessageType.NoErrorMessage, DateTime.UtcNow)); @@ -294,10 +303,9 @@ public void GetBidAuctionLots(Character player, int page) player.SendPacket(new SCAuctionSearchedPacket(page, dividedLists[page].Length, dividedLists[page].ToList(), (short)ErrorMessageType.NoErrorMessage, DateTime.UtcNow)); } - public AuctionLot GetCheapestAuctionLot(uint templateId) + private AuctionLot GetCheapestAuctionLot(uint templateId) { var tempList = AuctionLots.Where(lot => lot.Item.TemplateId == templateId).ToList(); - if (tempList.Count <= 0) { return null; @@ -320,64 +328,51 @@ public void CheapestAuctionLot(Character player, uint templateId, byte itemGrade player.SendPacket(new SCAuctionLowestPricePacket(templateId, itemGrade, DirectMoney)); } - public static string GetLocalizedItemNameById(uint id) + private static string GetLocalizedItemNameById(uint id) { return LocalizationManager.Instance.Get("items", "name", id, ItemManager.Instance.GetTemplate(id).Name ?? ""); } - public ulong GetNextId() + private ulong GetNextId() { - ulong nextId = 0; - foreach (var item in AuctionLots) - { - if (nextId < item.Id) - nextId = item.Id; - } - return nextId + 1; + if (AuctionLots.Count == 0) + return 1; + + var maxId = AuctionLots.Max(item => item.Id); + if (maxId == ulong.MaxValue) + throw new OverflowException("No more IDs available."); + + return maxId + 1; } - public void RemoveAuctionLot(AuctionLot itemToRemove) + private void RemoveAuctionLot(AuctionLot itemToRemove) { - //if (itemToRemove.ClientName == "") // Testing feature. Relists an item if the server listed it. - //{ - // itemToRemove.EndTime = DateTime.UtcNow.AddHours(48); - // return; - //} - lock (AuctionLots) + if (!AuctionLots.Contains(itemToRemove)) { - lock (_deletedAuctionItemIds) - { - if (AuctionLots.Contains(itemToRemove)) - { - _deletedAuctionItemIds.Add((long)itemToRemove.Id); - AuctionLots.Remove(itemToRemove); - } - } + return; } + + AuctionIdManager.Instance.ReleaseId((uint)itemToRemove.Id); + _deletedAuctionItemIds.Add((long)itemToRemove.Id); + AuctionLots.TryTake(out itemToRemove); } public void AddAuctionLot(AuctionLot lot) { - lock (AuctionLots) - { - AuctionLots.Add(lot); - } + AuctionLots.Add(lot); } public void UpdateAuctionHouse() { Logger.Trace("Updating Auction House!"); - lock (AuctionLots) - { - var itemsToRemove = AuctionLots.Where(c => DateTime.UtcNow > c.EndTime); + var itemsToRemove = AuctionLots.Where(c => DateTime.UtcNow > c.EndTime).ToList(); - foreach (var item in itemsToRemove) - { - if (item.BidderId != 0) - RemoveAuctionLotSold(item, item.BidderName, item.BidMoney); - else - RemoveAuctionLotFail(item); - } + foreach (var item in itemsToRemove) + { + if (item.BidderId != 0) + RemoveAuctionLotSold(item, item.BidderName, item.BidMoney); + else + RemoveAuctionLotFail(item); } } @@ -390,7 +385,7 @@ public AuctionLot CreateAuctionLot(Character player, Item itemToList, int startP timeLeft = 6; // 6 hours break; case AuctionDuration.AuctionDuration12Hours: - timeLeft = 12; // 12 hours + timeLeft = 12; break; case AuctionDuration.AuctionDuration24Hours: timeLeft = 24; // 24 hours @@ -403,88 +398,87 @@ public AuctionLot CreateAuctionLot(Character player, Item itemToList, int startP break; } - var newAuctionLot = new AuctionLot(); - newAuctionLot.Id = GetNextId(); - newAuctionLot.Duration = duration; - - newAuctionLot.Item = itemToList; - - newAuctionLot.EndTime = DateTime.UtcNow.AddHours(timeLeft); - - newAuctionLot.WorldId = 1; - newAuctionLot.ClientId = player.Id; - newAuctionLot.ClientName = player.Name; - newAuctionLot.StartMoney = startPrice; - newAuctionLot.DirectMoney = buyoutPrice; - newAuctionLot.PostDate = DateTime.UtcNow; - newAuctionLot.ChargePercent = 1000; // added in 5+ - newAuctionLot.BidWorldId = 255; - newAuctionLot.BidderId = 0; - newAuctionLot.BidderName = ""; - newAuctionLot.BidMoney = 0; - newAuctionLot.Extra = 0; - newAuctionLot.MinStack = minStack; // added in 5+ - newAuctionLot.MaxStack = maxStack; // added in 5+ - newAuctionLot.IsDirty = true; + var newAuctionLot = new AuctionLot + { + Id = AuctionIdManager.Instance.GetNextId(), + Duration = duration, + Item = itemToList, + EndTime = DateTime.UtcNow.AddHours(timeLeft), + //EndTime = DateTime.UtcNow.AddMinutes(timeLeft), // TODO после проверки удалить + WorldId = 1, + ClientId = player.Id, + ClientName = player.Name, + StartMoney = startPrice, + DirectMoney = buyoutPrice, + PostDate = DateTime.UtcNow, + ChargePercent = 100, // added in 5+ + BidWorldId = 255, + BidderId = 0, + BidderName = "", + BidMoney = 0, + Extra = 0, + MinStack = minStack, // added in 5+ + MaxStack = maxStack, // added in 5+ + IsDirty = true + }; return newAuctionLot; } public void Load() { - AuctionLots = []; - SoldsData = []; - _deletedAuctionItemIds = []; - - using (var connection = MySQL.CreateConnection()) + try { - using (var command = connection.CreateCommand()) + AuctionLots.Clear(); + SoldsData.Clear(); + _deletedAuctionItemIds.Clear(); + + using (var connection = MySQL.CreateConnection()) { - command.CommandText = "SELECT * FROM auction_house"; - command.Prepare(); - using (var reader = command.ExecuteReader()) + using (var command = connection.CreateCommand()) { - while (reader.Read()) + command.CommandText = "SELECT * FROM auction_house"; + command.Prepare(); + using (var reader = command.ExecuteReader()) { - var auctionLot = new AuctionLot(); - auctionLot.Id = reader.GetUInt64("id"); - auctionLot.Duration = (AuctionDuration)reader.GetByte("duration"); // 8 is 6 hours, 9 is 12 hours, 10 is 24 hours, 11 is 48 hours - - var itemId = reader.GetUInt32("item_id"); - var item = ItemManager.Instance.GetItemByItemId(itemId); - if (item == null) + while (reader.Read()) { - continue; + var auctionLot = new AuctionLot + { + Id = reader.GetUInt64("id"), + Duration = (AuctionDuration)reader.GetByte("duration"), // 8 is 6 hours, 9 is 12 hours, 10 is 24 hours, 11 is 48 hours + Item = ItemManager.Instance.GetItemByItemId(reader.GetUInt32("item_id")), + PostDate = reader.GetDateTime("post_date"), + EndTime = reader.GetDateTime("end_time"), + WorldId = reader.GetByte("world_id"), + ClientId = reader.GetUInt32("client_id"), + ClientName = reader.GetString("client_name"), + StartMoney = reader.GetInt32("start_money"), + DirectMoney = reader.GetInt32("direct_money"), + ChargePercent = reader.GetInt32("charge_percent"), // added in 5+ + BidWorldId = (byte)reader.GetInt32("bid_world_id"), + BidderId = reader.GetUInt32("bidder_id"), + BidderName = reader.GetString("bidder_name"), + BidMoney = reader.GetInt32("bid_money"), + Extra = reader.GetInt32("extra"), + MinStack = reader.GetInt32("min_stack"), // added in 5+ + MaxStack = reader.GetInt32("max_stack") // added in 5+ + }; + + AddAuctionLot(auctionLot); } - - auctionLot.EndTime = reader.GetDateTime("end_time"); - - auctionLot.WorldId = reader.GetByte("world_id"); - auctionLot.ClientId = reader.GetUInt32("client_id"); - auctionLot.ClientName = reader.GetString("client_name"); - auctionLot.StartMoney = reader.GetInt32("start_money"); - auctionLot.DirectMoney = reader.GetInt32("direct_money"); - - auctionLot.ChargePercent = reader.GetInt32("charge_percent"); // added in 5+ - - auctionLot.BidWorldId = (byte)reader.GetInt32("bid_world_id"); - auctionLot.BidderId = reader.GetUInt32("bidder_id"); - auctionLot.BidderName = reader.GetString("bidder_name"); - auctionLot.BidMoney = reader.GetInt32("bid_money"); - auctionLot.Extra = reader.GetInt32("extra"); - - auctionLot.MinStack = reader.GetInt32("min_stack"); // added in 5+ - auctionLot.MaxStack = reader.GetInt32("max_stack"); // added in 5+ - - AddAuctionLot(auctionLot); } } - } - ReadAuctionSoldsData(connection); + ReadAuctionSoldsData(connection); + } + var auctionTask = new AuctionHouseTask(); + TaskManager.Instance.Schedule(auctionTask, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5)); + } + catch (Exception ex) + { + Logger.Error($"Failed to load auction data: {ex.Message}"); } - var auctionTask = new AuctionHouseTask(); - TaskManager.Instance.Schedule(auctionTask, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5)); } public (int, int) Save(MySqlConnection connection, MySqlTransaction transaction) @@ -492,108 +486,62 @@ public void Load() var deletedCount = 0; var updatedCount = 0; - lock (_deletedAuctionItemIds) + if (_deletedAuctionItemIds.Count > 0) { - deletedCount = _deletedAuctionItemIds.Count; - if (_deletedAuctionItemIds.Count > 0) + using (var command = connection.CreateCommand()) { - using (var command = connection.CreateCommand()) - { - command.Connection = connection; - command.Transaction = transaction; - command.CommandText = "DELETE FROM auction_house WHERE `id` IN(" + string.Join(",", _deletedAuctionItemIds) + ")"; - command.Prepare(); - command.ExecuteNonQuery(); - } - _deletedAuctionItemIds.Clear(); + command.Connection = connection; + command.Transaction = transaction; + command.CommandText = "DELETE FROM auction_house WHERE `id` IN(" + string.Join(",", _deletedAuctionItemIds) + ")"; + command.Prepare(); + deletedCount = command.ExecuteNonQuery(); } + _deletedAuctionItemIds.Clear(); } var dirtyItems = AuctionLots.Where(c => c.IsDirty == true); - foreach (var mtbs in dirtyItems) + foreach (var lot in dirtyItems) { - if (mtbs.Item == null) + if (lot.Item == null) continue; - if (mtbs.Item.SlotType == SlotType.Invalid) + if (lot.Item.SlotType == SlotType.Invalid) { - // Only give an error if it has no owner, otherwise it's likely a BuyBack item - if (mtbs.Item.OwnerId <= 0) + if (lot.Item.OwnerId <= 0) continue; - // Try to re-attain the slot type by getting the owning container's type - if (mtbs.Item._holdingContainer != null) + if (lot.Item._holdingContainer != null) { - mtbs.Item.SlotType = ItemManager.Instance.GetContainerSlotTypeByContainerId(mtbs.Item._holdingContainer.ContainerId); + lot.Item.SlotType = ItemManager.Instance.GetContainerSlotTypeByContainerId(lot.Item._holdingContainer.ContainerId); } - // If the slot type changed, give a warning, otherwise skip this save - if (mtbs.Item.SlotType != SlotType.Invalid) + if (lot.Item.SlotType != SlotType.Invalid) { - Logger.Warn($"Slot type for {mtbs.Item.Id} was None, changing to {mtbs.Item.SlotType}"); + Logger.Warn($"Slot type for {lot.Item.Id} was None, changing to {lot.Item.SlotType}"); } else { continue; } } - if (!Enum.IsDefined(typeof(SlotType), mtbs.Item.SlotType)) + if (!Enum.IsDefined(typeof(SlotType), lot.Item.SlotType)) { - Logger.Warn($"Found SlotType.{mtbs.Item.SlotType} in itemslist, skipping ID:{mtbs.Item.Id} - Template:{mtbs.Item.TemplateId}"); + Logger.Warn($"Found SlotType.{lot.Item.SlotType} in itemslist, skipping ID:{lot.Item.Id} - Template:{lot.Item.TemplateId}"); continue; } var details = new Commons.Network.PacketStream(); - mtbs.Item.WriteDetails(details); + lot.Item.WriteDetails(details); using (var command = connection.CreateCommand()) { - // TODO отключим сохранение в базу - command.Connection = connection; command.Transaction = transaction; - - command.CommandText = "REPLACE INTO auction_house(" + - "`id`, `duration`," + - " `item_id`," + - "`end_time`," + - " `world_id`, `client_id`, `client_name`," + - " `start_money`, `direct_money`, `charge_percent`," + - " `bid_world_id`, `bidder_id`, `bidder_name`," + - " `bid_money`, `extra`, `min_stack`, `max_stack`" + - ") VALUES (" + - "@id, @duration," + - " @item_id," + - "@end_time," + - " @world_id, @client_id, @client_name," + - " @start_money, @direct_money, @charge_percent," + - " @bid_world_id, @bidder_id, @bidder_name," + - " @bid_money, @extra, @min_stack, @max_stack)"; - - command.Parameters.AddWithValue("@id", mtbs.Id); - command.Parameters.AddWithValue("@duration", (byte)mtbs.Duration); - - command.Parameters.AddWithValue("@item_id", mtbs.Item.Id); // item.Id - - command.Parameters.AddWithValue("@end_time", mtbs.EndTime); - command.Parameters.AddWithValue("@world_id", mtbs.WorldId); - command.Parameters.AddWithValue("@client_id", mtbs.ClientId); - command.Parameters.AddWithValue("@client_name", mtbs.ClientName); - command.Parameters.AddWithValue("@start_money", mtbs.StartMoney); - command.Parameters.AddWithValue("@direct_money", mtbs.DirectMoney); - command.Parameters.AddWithValue("@charge_percent", mtbs.ChargePercent); // added in 5+ - command.Parameters.AddWithValue("@bid_world_id", mtbs.BidWorldId); - command.Parameters.AddWithValue("@bidder_id", mtbs.BidderId); - command.Parameters.AddWithValue("@bidder_name", mtbs.BidderName); - command.Parameters.AddWithValue("@bid_money", mtbs.BidMoney); - command.Parameters.AddWithValue("@extra", mtbs.Extra); - command.Parameters.AddWithValue("@min_stack", mtbs.MinStack); // added in 5+ - command.Parameters.AddWithValue("@max_stack", mtbs.MaxStack); // added in 5+ - + command.CommandText = BuildInsertQuery(lot); + AddParametersToCommand(command, lot); command.Prepare(); - command.ExecuteNonQuery(); - updatedCount++; - mtbs.IsDirty = false; + updatedCount += command.ExecuteNonQuery(); + lot.IsDirty = false; } } @@ -602,49 +550,80 @@ public void Load() return (updatedCount, deletedCount); } - private List SortArticles(List articles, AuctionSearchSortKind kind, AuctionSearchSortOrder order) + private string BuildInsertQuery(AuctionLot lot) { - if (kind == AuctionSearchSortKind.BidPrice) - { - if (order == AuctionSearchSortOrder.Asc) - { - return articles.OrderBy(o => o.BidMoney).ToList(); - } - - return articles.OrderByDescending(o => o.BidMoney).ToList(); - } - - if (kind == AuctionSearchSortKind.DirectPrice) - { - if (order == AuctionSearchSortOrder.Asc) - { - return articles.OrderBy(o => o.DirectMoney).ToList(); - } - - return articles.OrderByDescending(o => o.DirectMoney).ToList(); - } + var sb = new StringBuilder(); + sb.Append("REPLACE INTO auction_house("); + sb.Append("`id`, `duration`,"); + sb.Append(" `item_id`,"); + sb.Append("`post_date`, `end_time`,"); + sb.Append(" `world_id`, `client_id`, `client_name`,"); + sb.Append(" `start_money`, `direct_money`, `charge_percent`,"); + sb.Append(" `bid_world_id`, `bidder_id`, `bidder_name`,"); + sb.Append(" `bid_money`, `extra`, `min_stack`, `max_stack`"); + sb.Append(") VALUES ("); + sb.Append("@id, @duration,"); + sb.Append(" @item_id,"); + sb.Append("@post_date, @end_time,"); + sb.Append(" @world_id, @client_id, @client_name,"); + sb.Append(" @start_money, @direct_money, @charge_percent,"); + sb.Append(" @bid_world_id, @bidder_id, @bidder_name,"); + sb.Append(" @bid_money, @extra, @min_stack, @max_stack)"); + + return sb.ToString(); + } - if (kind == AuctionSearchSortKind.ExpireDate) // TODO This will need to be fixed later due to varying durations - { - if (order == AuctionSearchSortOrder.Asc) - { - return articles.OrderBy(o => o.PostDate).ToList(); - } + private void AddParametersToCommand(MySqlCommand command, AuctionLot lot) + { + command.Parameters.AddWithValue("@id", lot.Id); + command.Parameters.AddWithValue("@duration", (byte)lot.Duration); + command.Parameters.AddWithValue("@item_id", lot.Item.Id); + command.Parameters.AddWithValue("@post_date", lot.PostDate); + command.Parameters.AddWithValue("@end_time", lot.EndTime); + command.Parameters.AddWithValue("@world_id", lot.WorldId); + command.Parameters.AddWithValue("@client_id", lot.ClientId); + command.Parameters.AddWithValue("@client_name", lot.ClientName); + command.Parameters.AddWithValue("@start_money", lot.StartMoney); + command.Parameters.AddWithValue("@direct_money", lot.DirectMoney); + command.Parameters.AddWithValue("@charge_percent", lot.ChargePercent); // added in 5+ + command.Parameters.AddWithValue("@bid_world_id", lot.BidWorldId); + command.Parameters.AddWithValue("@bidder_id", lot.BidderId); + command.Parameters.AddWithValue("@bidder_name", lot.BidderName); + command.Parameters.AddWithValue("@bid_money", lot.BidMoney); + command.Parameters.AddWithValue("@extra", lot.Extra); + command.Parameters.AddWithValue("@min_stack", lot.MinStack); // added in 5+ + command.Parameters.AddWithValue("@max_stack", lot.MaxStack); // added in 5+ + } - return articles.OrderByDescending(o => o.PostDate).ToList(); - } + private List SortArticles(List articles, AuctionSearchSortKind kind, AuctionSearchSortOrder order) + { + var sortedArticles = articles.AsQueryable(); - if (kind == AuctionSearchSortKind.ItemLevel) + switch (kind) { - if (order == AuctionSearchSortOrder.Asc) - { - return articles.OrderBy(o => o.Item.Template.Level).ToList(); - } - - return articles.OrderByDescending(o => o.Item.Template.Level).ToList(); + case AuctionSearchSortKind.BidPrice: + sortedArticles = order == AuctionSearchSortOrder.Asc + ? sortedArticles.OrderBy(o => o.BidMoney) + : sortedArticles.OrderByDescending(o => o.BidMoney); + break; + case AuctionSearchSortKind.DirectPrice: + sortedArticles = order == AuctionSearchSortOrder.Asc + ? sortedArticles.OrderBy(o => o.DirectMoney) + : sortedArticles.OrderByDescending(o => o.DirectMoney); + break; + case AuctionSearchSortKind.ExpireDate: + sortedArticles = order == AuctionSearchSortOrder.Asc + ? sortedArticles.OrderBy(o => o.PostDate) + : sortedArticles.OrderByDescending(o => o.PostDate); + break; + case AuctionSearchSortKind.ItemLevel: + sortedArticles = order == AuctionSearchSortOrder.Asc + ? sortedArticles.OrderBy(o => o.Item.Template.Level) + : sortedArticles.OrderByDescending(o => o.Item.Template.Level); + break; } - return articles; + return sortedArticles.ToList(); } public void SearchAuctionLots(Character player, AuctionSearch search) @@ -660,6 +639,7 @@ public void SearchAuctionLots(Character player, AuctionSearch search) var settings = template.AuctionSettings; template.Name = GetLocalizedItemNameById(template.Id); + // Проверка по ClientId if (search.ClientId != 0 && lot.ClientId != search.ClientId) { @@ -762,7 +742,7 @@ public void PostLotOnAuction(Character player, uint npcId, uint npcId2, ulong it return; } - player.Inventory.AuctionAttachments.AddOrMoveExistingItem(ItemTaskType.Auction, item); + player.Inventory.AuctionAttachments.AddOrMoveExistingItem2(ItemTaskType.Auction, item); AddAuctionLot(lot); player.SendPacket(new SCAuctionPostedPacket(lot)); @@ -899,9 +879,6 @@ public List GetSalesForLast14Days(uint itemTemplateId, byte itemGra private List GetLast14AuctionSoldByItemId(MySqlConnection connection, (uint itemTemplateId, byte itemGradeId) key) { - - //public static List<(DateTime Date, AuctionSold Sold)> GetLast14AuctionSoldByItemId(MySqlConnection connection, (uint itemTemplateId, byte itemGradeId) key) - // Список для хранения данных var last14AuctionSold = new List(); @@ -1061,7 +1038,6 @@ private void SaveSoldsData(MySqlConnection connection) SaveAuctionSold(connection, sold, date); } } - } catch (Exception ex) { @@ -1089,3 +1065,4 @@ private static void SaveAuctionSold(MySqlConnection connection, AuctionSold auct command.ExecuteNonQuery(); } } + diff --git a/AAEmu.Game/Core/Managers/HousingManager.cs b/AAEmu.Game/Core/Managers/HousingManager.cs index 45fa322ba4..c560049f26 100644 --- a/AAEmu.Game/Core/Managers/HousingManager.cs +++ b/AAEmu.Game/Core/Managers/HousingManager.cs @@ -22,7 +22,6 @@ using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; using AAEmu.Game.Models.Game.Mails; -using AAEmu.Game.Models.Game.Mails.Static; using AAEmu.Game.Models.Game.Skills; using AAEmu.Game.Models.Game.World.Transform; using AAEmu.Game.Models.StaticValues; diff --git a/AAEmu.Game/Core/Managers/Id/AuctionIdManager.cs b/AAEmu.Game/Core/Managers/Id/AuctionIdManager.cs new file mode 100644 index 0000000000..9367e7e5dd --- /dev/null +++ b/AAEmu.Game/Core/Managers/Id/AuctionIdManager.cs @@ -0,0 +1,18 @@ +using AAEmu.Game.Utils; + +namespace AAEmu.Game.Core.Managers.Id; + +public class AuctionIdManager : IdManager +{ + private static AuctionIdManager _instance; + private const uint FirstId = 0x00000001; + private const uint LastId = 0xFFFFFFFF; + private static readonly uint[] Exclude = System.Array.Empty(); + private static readonly string[,] ObjTables = { { "auction_house", "id" } }; + + public static AuctionIdManager Instance => _instance ?? (_instance = new AuctionIdManager()); + + public AuctionIdManager() : base("AuctionIdManager", FirstId, LastId, ObjTables, Exclude) + { + } +} diff --git a/AAEmu.Game/Core/Managers/ItemManager.cs b/AAEmu.Game/Core/Managers/ItemManager.cs index 2ead2069ba..1b1d1cebbf 100644 --- a/AAEmu.Game/Core/Managers/ItemManager.cs +++ b/AAEmu.Game/Core/Managers/ItemManager.cs @@ -253,6 +253,8 @@ public List CreateLootDropItems(uint npcId, BaseUnit killer) // Generate the actual loot foreach (var lootPackDropping in lootPackDroppingNpcs) { + Logger.Debug($"CreateLootDropItems: lootPackDropping.LootPackId={lootPackDropping.LootPackId}"); + var lootPack = LootGameData.Instance.GetPack(lootPackDropping.LootPackId); if (lootPack == null) continue; @@ -278,6 +280,8 @@ public List GetLootConvertFish(uint templateId) foreach (var lootPackConvertFish in lootPackConvertFishes) { + Logger.Debug($"GetLootConvertFish: lootPackConvertFish.LootPackId={lootPackConvertFish.LootPackId}"); + var lootPacks = LootGameData.Instance.GetPack(lootPackConvertFish.LootPackId); var dropRateMax = (uint)0; for (var ui = 0; ui < lootPacks.Loots?.Count; ui++) diff --git a/AAEmu.Game/Core/Managers/MailManager.cs b/AAEmu.Game/Core/Managers/MailManager.cs index 103d9b120f..9c03b682d2 100644 --- a/AAEmu.Game/Core/Managers/MailManager.cs +++ b/AAEmu.Game/Core/Managers/MailManager.cs @@ -136,7 +136,7 @@ public void Load() tempMail.Header.SenderName = reader.GetString("sender_name"); tempMail.Header.Attachments = (byte)reader.GetInt32("attachment_count"); tempMail.Header.ReceiverId = reader.GetUInt32("receiver_id"); - tempMail.Header.Returned = (reader.GetInt32("returned") != 0); + tempMail.Header.Returned = reader.GetInt32("returned") != 0; tempMail.Header.Extra = reader.GetInt64("extra"); tempMail.Body.Text = reader.GetString("text"); @@ -178,7 +178,7 @@ public void Load() tempMail.Header.Attachments = (byte)attachmentCount; // Set internal delivered flag - tempMail.IsDelivered = (tempMail.Body.RecvDate <= DateTime.UtcNow); + tempMail.IsDelivered = tempMail.Body.RecvDate <= DateTime.UtcNow; tempMail.IsDirty = false; // Remove from delete list if it's a recycled Id @@ -285,13 +285,13 @@ public Dictionary GetCurrentMailList(Character character) character.Mails.UnreadMailCount.ResetReceived(); foreach (var mail in tempMails) { - character.Mails.UnreadMailCount.UpdateReceived(mail.Value.MailType, 1); - if (mail.Value.Header.Status != MailStatus.Read) + if (mail.Value.Header.Status == MailStatus.Unread || mail.Value.Header.Status == MailStatus.Unpaid) { + character.Mails.UnreadMailCount.UpdateReceived(mail.Value.MailType, 1); character.Mails.UnreadMailCount.UpdateUnreadReceived(mail.Value.MailType, 1); - var addBody = (mail.Value.MailType == MailType.Charged); + var addBody = mail.Value.MailType == MailType.Charged; - //character.SendPacket(new SCGotMailPacket(mail.Value.Header, character.Mails.UnreadMailCount, false, addBody ? mail.Value.Body : null)); + character.SendPacket(new SCGotMailPacket(mail.Value.Header, character.Mails.UnreadMailCount, false, addBody ? mail.Value.Body : null)); mail.Value.IsDelivered = true; } } @@ -300,15 +300,15 @@ public Dictionary GetCurrentMailList(Character character) public static bool NotifyNewMailByNameIfOnline(BaseMail m, string receiverName) { - Logger.Trace($"NotifyNewMailByNameIfOnline() - {receiverName}"); + Logger.Debug($"NotifyNewMailByNameIfOnline() - {receiverName}"); // If unread and ready to deliver - if ((m.Header.Status != MailStatus.Read) && (m.Body.RecvDate <= DateTime.UtcNow) && (m.IsDelivered == false)) + if ((m.Header.Status == MailStatus.Unread || m.Header.Status == MailStatus.Unpaid) && m.Body.RecvDate <= DateTime.UtcNow && m.IsDelivered == false) { var player = WorldManager.Instance.GetCharacter(receiverName); if (player != null) { // TODO: Mia mail stuff - var addBody = (m.MailType == MailType.Charged); + var addBody = m.MailType == MailType.Charged; player.Mails.UnreadMailCount.UpdateReceived(m.MailType, 1); player.Mails.UnreadMailCount.UpdateUnreadReceived(m.MailType, 1); @@ -326,9 +326,12 @@ public static bool NotifyDeleteMailByNameIfOnline(BaseMail m, string receiverNam var player = WorldManager.Instance.GetCharacter(receiverName); if (player != null) { - player.Mails.UnreadMailCount.UpdateReceived(m.MailType, -1); - if (m.Header.Status != MailStatus.Read) + if (m.Header.Status == MailStatus.Unread) + { + player.Mails.UnreadMailCount.UpdateReceived(m.MailType, -1); player.Mails.UnreadMailCount.UpdateUnreadReceived(m.MailType, -1); + } + player.SendPacket(new SCMailDeletedPacket(false, m.Id, true, player.Mails.UnreadMailCount)); return true; } @@ -339,7 +342,7 @@ public void CheckAllMailTimings() { // Deliver yet "undelivered" mails Logger.Trace("CheckAllMailTimings"); - var undeliveredMails = _allPlayerMails.Where(x => (x.Value.Body.RecvDate <= DateTime.UtcNow) && (x.Value.IsDelivered == false)).ToDictionary(x => x.Key, x => x.Value); + var undeliveredMails = _allPlayerMails.Where(x => x.Value.Body.RecvDate <= DateTime.UtcNow && x.Value.IsDelivered == false).ToDictionary(x => x.Key, x => x.Value); var delivered = 0; foreach (var mail in undeliveredMails) if (NotifyNewMailByNameIfOnline(mail.Value, mail.Value.Header.ReceiverName)) @@ -367,7 +370,7 @@ public bool PayChargeMoney(Character character, long mailId, bool autoUseAAPoint } var houseId = (uint)(mail.Header.Extra & 0xFFFFFFFF); // Extract house DB Id from Extra - var houseZoneGroup = ((mail.Header.Extra >> 48) & 0xFFFF); // Extract zone group Id from Extra + var houseZoneGroup = (mail.Header.Extra >> 48) & 0xFFFF; // Extract zone group Id from Extra var house = HousingManager.Instance.GetHouseById(houseId); if (house == null) @@ -395,7 +398,7 @@ public bool PayChargeMoney(Character character, long mailId, bool autoUseAAPoint { var c = consumedCerts; // Use Bound First - if ((userBoundTaxCount > 0) && (c > 0)) + if (userBoundTaxCount > 0 && c > 0) { if (c > userBoundTaxCount) c = userBoundTaxCount; @@ -403,7 +406,7 @@ public bool PayChargeMoney(Character character, long mailId, bool autoUseAAPoint consumedCerts -= c; } c = consumedCerts; - if ((userTaxCount > 0) && (c > 0)) + if (userTaxCount > 0 && c > 0) { if (c > userTaxCount) c = userTaxCount; @@ -437,10 +440,11 @@ public bool PayChargeMoney(Character character, long mailId, bool autoUseAAPoint Logger.Error("Could not update protection time when paying taxes, mailId {0}", mail.Id); else { - if (mail.Header.Status != MailStatus.Read) + if (mail.Header.Status == MailStatus.Unread) { mail.Header.Status = MailStatus.Read; character.Mails.UnreadMailCount.UpdateReceived(mail.MailType, -1); + character.Mails.UnreadMailCount.UpdateUnreadReceived(mail.MailType, -1); } character.SendPacket(new SCChargeMoneyPaidPacket(mail.Id)); @@ -530,7 +534,7 @@ public static List CreateQuestRewardMails(ICharacter character, Quest // Distribute the quest rewards foreach(var item in totalRewardsItemsList) { - if ((mail == null) || (mail.Body.Attachments.Count >= 10)) + if (mail == null || mail.Body.Attachments.Count >= 10) { mail = new MailPlayerToPlayer(character, character.Name); mail.Header.SenderId = (uint)SystemMailSenderKind.None; diff --git a/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveEquipmentPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveEquipmentPacket.cs index 53afc9ff4a..d1bda8dd6b 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveEquipmentPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSChangeSlaveEquipmentPacket.cs @@ -143,6 +143,11 @@ private static void DespawnDoodad(Slave slave, uint doodadId) { var doodad = slave.GetDoodadByItemTemplateId(doodadId); //doodad?.DoDespawn(doodad); + if (doodad is null) + { + return; + } + doodad.IsPersistent = false; doodad.Despawn = DateTime.UtcNow; SpawnManager.Instance.AddDespawn(doodad); @@ -152,6 +157,11 @@ private static void DespawnDoodad(Slave slave, uint doodadId) private static void DespawnSlave(Slave slave, uint slaveId) { var attachedSlave = slave.GetSlaveByItemTemplateId(slaveId); + if (attachedSlave is null) + { + return; + } + WorldManager.Instance.RemoveObject(attachedSlave); attachedSlave.Despawn = DateTime.UtcNow; SpawnManager.Instance.AddDespawn(attachedSlave); diff --git a/AAEmu.Game/Core/Packets/C2G/CSICSBuyGoodPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSICSBuyGoodPacket.cs index 9d72f72fd6..f93bd29e41 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSICSBuyGoodPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSICSBuyGoodPacket.cs @@ -6,7 +6,6 @@ using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Network.Game; using AAEmu.Game.Core.Packets.G2C; -using AAEmu.Game.Models.Game; using AAEmu.Game.Models.Game.CashShop; using AAEmu.Game.Models.Tasks.CashShop; @@ -20,7 +19,7 @@ public CSICSBuyGoodPacket() : base(CSOffsets.CSICSBuyGoodRequestPacket, 5) public override void Read(PacketStream stream) { - var buyer = Connection.ActiveChar; + //var buyer = Connection.ActiveChar; var buyList = new List(); var thisChar = Connection.ActiveChar; byte buyMode = 1; // No idea what this means @@ -53,8 +52,7 @@ public override void Read(PacketStream stream) if (sku == null) { - Logger.Warn( - $"{Connection.ActiveChar.Name} is trying to shop from ShopItem: {shopItem.ShopId}, but with invalid index: {detailIndex}"); + Logger.Warn($"{Connection.ActiveChar.Name} is trying to shop from ShopItem: {shopItem.ShopId}, but with invalid index: {detailIndex}"); continue; } diff --git a/AAEmu.Game/Core/Packets/C2G/CSTakeAllAttachmentItemPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSTakeAllAttachmentItemPacket.cs index 76e8a31dfe..42f6b9e630 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSTakeAllAttachmentItemPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSTakeAllAttachmentItemPacket.cs @@ -18,10 +18,10 @@ public override void Read(PacketStream stream) if (Connection.ActiveChar.Mails.GetAttached(mailId, true, true, true)) { Connection.ActiveChar.SendPacket(new SCMailStatusUpdatedPacket(false, mailId, MailStatus.Read)); - Connection.ActiveChar.Mails.DeleteMail(mailId, false); Connection.ActiveChar.Mails.SendUnreadMailCount(); + return; } - else - Logger.Debug($"CSTakeAllAttachmentItemPacket - Failed for: {mailId} -> {Connection.ActiveChar.Name}"); + + Logger.Debug($"CSTakeAllAttachmentItemPacket - Failed for: {mailId} -> {Connection.ActiveChar.Name}"); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentMoneyPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentMoneyPacket.cs index 2bc5726b87..37382c6e38 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentMoneyPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentMoneyPacket.cs @@ -12,6 +12,6 @@ public CSTakeAttachmentMoneyPacket() : base(CSOffsets.CSTakeAttachmentMoneyPacke public override void Read(PacketStream stream) { var mailId = stream.ReadInt64(); - Connection.ActiveChar.Mails.GetAttached(mailId, true, false, true); + Connection.ActiveChar.Mails.GetAttached(mailId, true, false, false); } } diff --git a/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentSequentiallyPacket.cs b/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentSequentiallyPacket.cs index ecfe4edb82..0f61caa584 100644 --- a/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentSequentiallyPacket.cs +++ b/AAEmu.Game/Core/Packets/C2G/CSTakeAttachmentSequentiallyPacket.cs @@ -1,7 +1,9 @@ using AAEmu.Commons.Network; using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Network.Game; -using AAEmu.Game.Models.Game; +using AAEmu.Game.Core.Packets.G2C; +using AAEmu.Game.Models.Game.Mails; +using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Core.Packets.C2G; @@ -13,17 +15,47 @@ public CSTakeAttachmentSequentiallyPacket() : base(CSOffsets.CSTakeAttachmentSeq public override void Read(PacketStream stream) { + var takeMoney = false; + var takeItems = false; + var takeAllSelected = true; + var mailId = stream.ReadInt64(); Logger.Debug("TakeAttachmentSequentially, mailId: {0}", mailId); var mail = MailManager.Instance.GetMailById(mailId); + if (mail is null) + { + return; + } if (mail.Header.ReceiverId != Connection.ActiveChar.Id) // just a check for hackers trying to steal mails { Connection.ActiveChar.SendErrorMessage(ErrorMessageType.MailInvalid); } else { - Connection.ActiveChar.Mails.GetAttached(mailId, true, true, true); + if (mail.Body.CopperCoins > 0 || mail.Body.BillingAmount > 0 || mail.Body.MoneyAmount2 > 0) + { + takeMoney = true; + } + + if (mail.Body.Attachments.Count > 0) + { + takeItems = true; + } + + if (mail.MailType == MailType.Charged) + { + takeAllSelected = false; + } + + if (Connection.ActiveChar.Mails.GetAttached(mailId, takeMoney, takeItems, takeAllSelected)) + { + Connection.ActiveChar.SendPacket(new SCMailStatusUpdatedPacket(false, mailId, MailStatus.Read)); + Connection.ActiveChar.Mails.SendUnreadMailCount(); + return; + } + + Logger.Debug($"CSTakeAllAttachmentItemPacket - Failed for: {mailId} -> {Connection.ActiveChar.Name}"); } } -} \ No newline at end of file +} diff --git a/AAEmu.Game/GameService.cs b/AAEmu.Game/GameService.cs index a733024581..a697ea3a2b 100644 --- a/AAEmu.Game/GameService.cs +++ b/AAEmu.Game/GameService.cs @@ -103,6 +103,7 @@ public async Task StartAsync(CancellationToken cancellationToken) ShipyardManager.Instance.Initialize(); // SkillTlIdManager.Instance.Initialize(); IndunManager.Instance.Initialize(); + AuctionIdManager.Instance.Initialize(); GameDataManager.Instance.LoadGameData(); QuestManager.Instance.Load(); diff --git a/AAEmu.Game/Models/Game/Char/CharacterMails.cs b/AAEmu.Game/Models/Game/Char/CharacterMails.cs index 3b640a7821..62dba2f6bf 100644 --- a/AAEmu.Game/Models/Game/Char/CharacterMails.cs +++ b/AAEmu.Game/Models/Game/Char/CharacterMails.cs @@ -28,18 +28,18 @@ public CharacterMails(Character self) UnreadMailCount.ResetReceived(); } - public void SendMailList(byte mailBoxListKind, int startIdx, int sentCnt, bool isRecover, bool isTest) + public void SendMailList(byte mailBoxListKind, int startIdx = 0, int sentCnt = 0, bool isRecover = false, bool isTest = false) { SendMailIndex = 0; var mailList = MailManager.Instance.GetCurrentMailList(Self).Values.ToList(); var total = mailList.Count; - SendMailList(mailBoxListKind, mailList[SendMailIndex].Header, total); - + Self.SendPacket(new SCMailListPacket(true, total, mailList[SendMailIndex].Header, mailBoxListKind)); + UnreadMailCount.UpdateSend(1); SendMailIndex++; - if (SendMailIndex < total - 1) + if (SendMailIndex < total) { return; } @@ -55,7 +55,9 @@ public void SendMailListContinue(byte mailBoxListKind) if (SendMailIndex < total) { - SendMailList(mailBoxListKind, mailList[SendMailIndex].Header, total); + //SendMailList(mailBoxListKind, mailList[SendMailIndex].Header, total); + Self.SendPacket(new SCMailListPacket(true, total, mailList[SendMailIndex].Header, mailBoxListKind)); + UnreadMailCount.UpdateSend(1); SendMailIndex++; return; } @@ -90,9 +92,8 @@ public void ReadMail(bool isSent, long id) mail.Header.Status = MailStatus.Read; mail.IsDelivered = true; } + Self.SendPacket(new SCMailReceiverOpenedPacket(mail.Id, mail.OpenDate)); Self.SendPacket(new SCMailBodyPacket(false, isSent, mail.Body, true, UnreadMailCount)); - //Self.SendPacket(new SCMailStatusUpdatedPacket(isSent, id, mail.Header.Status)); - //SendUnreadMailCount(); } } @@ -150,23 +151,23 @@ public MailResult SendMailToPlayer(MailType mailType, string receiverName, strin // Send it if (mail.Send()) { + UnreadMailCount.UpdateSend(1); Self.SendPacket(new SCMailSentPacket(mail.Header, itemSlots.ToArray(), UnreadMailCount)); // Take the fee Self.SubtractMoney(SlotType.Bag, mailFee + money0); return MailResult.Success; } - else - { - return MailResult.MailErrorOccurred; - } + + return MailResult.MailErrorOccurred; } public bool GetAttached(long mailId, bool takeMoney, bool takeItems, bool takeAllSelected, ulong specifiedItemId = 0) { var res = true; + var itemSlotList = new List(); + if (MailManager.Instance._allPlayerMails.TryGetValue(mailId, out var thisMail)) { - var tookMoney = false; if (thisMail.MailType == MailType.AucOffSuccess && thisMail.Body.CopperCoins > 0 && takeMoney) { if (Self.LaborPower < 1) @@ -179,21 +180,24 @@ public bool GetAttached(long mailId, bool takeMoney, bool takeItems, bool takeAl Self.ChangeLabor(-1, (int)ActabilityType.Commerce); } } + + // Клиент шлет пакет CSTakeAttachmentSequentiallyPacket по количеству прикрепленных предметов. + // Сначала для получения денег, затем получение предметов. + if (thisMail.Body.CopperCoins > 0 && takeMoney) { + // Money Self.ChangeMoney(SlotType.Bag, thisMail.Body.CopperCoins); thisMail.Body.CopperCoins = 0; thisMail.Header.Attachments -= 1; - tookMoney = true; - } - if (thisMail.Body.CopperCoins == 0 && takeMoney) - takeMoney = false; - - var itemSlotList = new List(); - // Check if items need to be taken, and add them to a list - if (takeItems) + // Send attachments taken packets (if needed) + Self.SendPacket(new SCMailAttachmentTakenPacket(mailId, true, false, takeAllSelected, new List())); + } + else if (takeItems && thisMail.Header.Attachments > 0) { + // Items + // Check if items need to be taken, and add them to a list var toRemove = new List(); foreach (var itemAttachment in thisMail.Body.Attachments) { @@ -203,6 +207,21 @@ public bool GetAttached(long mailId, bool takeMoney, bool takeItems, bool takeAl continue; } + // добавим проверку на TemplateItem = 500 (Money) + if (itemAttachment.TemplateId == 500) + { + // Money + Self.ChangeMoney(SlotType.Bag, itemAttachment.Count); + var iial = new ItemIdAndLocation(); + iial.Id = itemAttachment.Id; + iial.SlotType = 0; + iial.Slot = 0; + itemSlotList.Add(iial); + thisMail.Header.Attachments -= 1; + toRemove.Add(itemAttachment); + break; + } + // Sanity-check if (itemAttachment.Id != 0) { @@ -225,48 +244,36 @@ public bool GetAttached(long mailId, bool takeMoney, bool takeItems, bool takeAl var iial = new ItemIdAndLocation(); iial.Id = itemAttachment.Id; - iial.SlotType = itemAttachment.SlotType; - iial.Slot = (byte)itemAttachment.Slot; + iial.SlotType = 0; //itemAttachment.SlotType; + iial.Slot = 0; //(byte)itemAttachment.Slot; // Move item to player inventory - if (Self.Inventory.Bag.AddOrMoveExistingItem(ItemTaskType.Mail, itemAttachment, stackItem != null ? stackItem.Slot : -1)) + if (Self.Inventory.Bag.AddOrMoveExistingItem2(ItemTaskType.Mail, itemAttachment, stackItem != null ? stackItem.Slot : -1)) { itemSlotList.Add(iial); thisMail.Header.Attachments -= 1; toRemove.Add(itemAttachment); + break; // обрабатываем каждый предмет по отдельности } - else - { - // Should technically never fail because of previous free slot check - throw new Exception("GetAttachmentFailedAddToBag"); - } - } - else - { - // Bag Full - Self.SendErrorMessage(ErrorMessageType.BagFull); - res = false; + + // Should technically never fail because of previous free slot check + throw new Exception("GetAttachmentFailedAddToBag"); } + + // Bag Full + Self.SendErrorMessage(ErrorMessageType.BagFull); + res = false; } } + // Removed those marked to be taken foreach (var ia in toRemove) { thisMail.Body.Attachments.Remove(ia); } - } - // Mark taken items - // Send attachments taken packets (if needed) - // Money - if (tookMoney) - { - Self.SendPacket(new SCMailAttachmentTakenPacket(mailId, true, false, takeAllSelected, new List())); - } - - // Items - if (itemSlotList.Count > 0) - { + // Mark taken items + // Send attachments taken packets (if needed) // Self.SendPacket(new SCAttachmentTakenPacket(mailId, takeMoney, false, takeAllSelected, itemSlotList)); /* * ZeromusXYZ: @@ -278,23 +285,20 @@ public bool GetAttached(long mailId, bool takeMoney, bool takeItems, bool takeAl { var dummyItemSlotList = new List(); dummyItemSlotList.Add(iSlot); - Self.SendPacket(new SCMailAttachmentTakenPacket(mailId, takeMoney, false, takeAllSelected, dummyItemSlotList)); + Self.SendPacket(new SCMailAttachmentTakenPacket(mailId, false, false, takeAllSelected, dummyItemSlotList)); } + + // Mark mail as read in case we took at least one item from it + // TODO: Make sure attachment settings and mail info is sent back correctly + // taking all attachments sometimes doesn't enable the delete button when getting attachments using "GetAllSelected" + // TODO: if source player is online, update their mail info (sent tab) } - // Mark mail as read in case we took at least one item from it - if (thisMail.Header.Status == MailStatus.Unread && (tookMoney || itemSlotList.Count > 0)) + if (thisMail.Header.Status == MailStatus.Unpaid && thisMail.MailType == MailType.Charged) { - thisMail.Header.Status = MailStatus.Read; - UnreadMailCount.UpdateReceived(thisMail.MailType, -1); - Self.SendPacket(new SCMailStatusUpdatedPacket(false, mailId, MailStatus.Read)); - SendUnreadMailCount(); + UnreadMailCount.UpdateUnreadReceived(thisMail.MailType, -1); + DeleteMail(thisMail.Id, false); } - - // TODO: Make sure attachment settings and mail info is sent back correctly - // taking all attachments sometimes doesn't enable the delete button when getting attachments using "GetAllSelected" - - // TODO: if source player is online, update their mail info (sent tab) } return res; @@ -304,22 +308,37 @@ public void DeleteMail(long id, bool isSent) { if (MailManager.Instance._allPlayerMails.ContainsKey(id) && !isSent) { - if (MailManager.Instance._allPlayerMails[id].Header.Attachments <= 0) + if (MailManager.Instance._allPlayerMails[id].Header.Attachments > 0) { - if (MailManager.Instance._allPlayerMails[id].Header.Status != MailStatus.Read) - { - UnreadMailCount.UpdateReceived(MailManager.Instance._allPlayerMails[id].MailType, -1); - UnreadMailCount.UpdateUnreadReceived(MailManager.Instance._allPlayerMails[id].MailType, -1); - Self.SendPacket(new SCMailDeletedPacket(isSent, id, true, UnreadMailCount)); - } - else - { - UnreadMailCount.UpdateReceived(MailManager.Instance._allPlayerMails[id].MailType, -1); - Self.SendPacket(new SCMailDeletedPacket(isSent, id, false, UnreadMailCount)); - } + return; + } + + if (MailManager.Instance._allPlayerMails[id].Header.Status == MailStatus.Unread) + { + UnreadMailCount.UpdateReceived(MailManager.Instance._allPlayerMails[id].MailType, -1); + UnreadMailCount.UpdateUnreadReceived(MailManager.Instance._allPlayerMails[id].MailType, -1); + Self.SendPacket(new SCMailDeletedPacket(isSent, id, true, UnreadMailCount)); + } + else + { + UnreadMailCount.UpdateReceived(MailManager.Instance._allPlayerMails[id].MailType, -1); + Self.SendPacket(new SCMailDeletedPacket(isSent, id, false, UnreadMailCount)); + } - MailManager.Instance.DeleteMail(id); + MailManager.Instance.DeleteMail(id); + UnreadMailCount.UpdateSend(-1); + } + else + { + if (MailManager.Instance._allPlayerMails[id].Header.Attachments > 0) + { + return; } + + UnreadMailCount.UpdateSend(-1); + Self.SendPacket(new SCMailDeletedPacket(isSent, id, false, UnreadMailCount)); + + MailManager.Instance.DeleteMail(id); } } diff --git a/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncLootPack.cs b/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncLootPack.cs index c8572d0b74..1750cd4b4d 100644 --- a/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncLootPack.cs +++ b/AAEmu.Game/Models/Game/DoodadObj/Funcs/DoodadFuncLootPack.cs @@ -16,6 +16,8 @@ public override void Use(BaseUnit caster, Doodad owner, uint skillId, int nextPh if (caster is not Character character) return; + Logger.Debug($"DoodadFuncLootPack: LootPackId={LootPackId}"); + var lootPack = LootGameData.Instance.GetPack(LootPackId); if (lootPack != null) { diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemTask.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemTask.cs index 50a23e1210..0a3f3e57d6 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemTask.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemTask.cs @@ -44,6 +44,9 @@ public ItemTaskLogType SetTlogT(ItemAction itemTask, SlotType slotType, bool add case ItemAction.Take: // 6 tlogT = ItemTaskLogType.MoveItem; break; + case ItemAction.Remove when slotType == SlotType.MailAttachment: // 7 + tlogT = ItemTaskLogType.RemoveItem; + break; case ItemAction.Remove when slotType == SlotType.Bag: // 7 tlogT = ItemTaskLogType.RemoveItem; break; diff --git a/AAEmu.Game/Models/Game/Items/Actions/ItemTaskType.cs b/AAEmu.Game/Models/Game/Items/Actions/ItemTaskType.cs index a3542c57e6..d6b0f7080e 100644 --- a/AAEmu.Game/Models/Game/Items/Actions/ItemTaskType.cs +++ b/AAEmu.Game/Models/Game/Items/Actions/ItemTaskType.cs @@ -33,14 +33,14 @@ public enum ItemTaskType : byte MateCreate, // mate-create CraftActSaved, // craft-act-saved CraftPaySaved, // craft-pay-saved - CraftPickupProduct = 27, // craft-pickup-product + CraftPickupProduct = 27, // craft-pickup-product CraftCancel, // craft-cancel MakeCraftOrderSheet, // make-craft-order-sheet RestoreCraftOrderSsheet, // restore-craft-order-sheet PostCcraftOrder, // post-craft-order - HouseCreation = 32, // 303-house-creation + HouseCreation = 32, // 303-house-creation HouseDeposit, // house-deposit - HouseBuilding = 34, // house-building + HouseBuilding = 34, // house-building PickupBloodstain, // pickup-bloodstain AutoLootDoodadItem, // 316-autoloot-doodad-item QuestStart = 37, // 401-quest-start @@ -53,8 +53,8 @@ public enum ItemTaskType : byte SkillEffectGainItemWithPos, // skill-effect-gain-item-with-pos SkillEffectSiegeTicket, // skill-effect-siege-ticket SkillEffectExpToItem, // skill-effect-exp-to-item - Auction = 48, // auction - Mail = 49, // mail + Auction = 48, // auction + Mail = 49, // mail Trade, // trade EnchantMagical, // enchant-magical EnchantPhysical, // enchant-physical @@ -63,7 +63,7 @@ public enum ItemTaskType : byte StoreSell = 55, // 315-store-sell StoreBuy = 56, // 313-314-store-buy TodReward, // tod-reward - CreateOriginUcc, // create-origin-ucc + CreateOriginUcc, // create-origin-ucc MakeUccDdye, // make-ucc-dye // GainItemWithUcc = 56 ImprintUcc = 60, // imprint-ucc @@ -81,7 +81,7 @@ public enum ItemTaskType : byte DemoDressOn, // demo-dress-on DemoClearBag, // demo-clear-bag DemoFillBag, // demo-fill-bag - SlaveDeath = 75, // slave-death + SlaveDeath = 75, // slave-death ExpeditionCreation, // expedition-creation DeclareExpeditionWar, // declare-expedition-war RecruitmentDecMoney, // recruitment-dec-money @@ -135,10 +135,10 @@ public enum ItemTaskType : byte ItemTaskThistimeUnpack, // item-task-thistime-unpack BuyPremiumService, // buy-premium-service-ingameshop BuyAaPoint, // buy-aa-point-ingameshop - TakeScheduleItem, // take-schedule-item + TakeScheduleItem, // take-schedule-item ScaleCap, // scale-cap HousePayTax, // house-pay-tax - BuyItemIngameshop, // buy-item-ingameshop + BuyItemIngameshop = 134, // buy-item-ingameshop ExchangeCashFromItem, // exchange-cash-from-item RepairSlaveEquipment, // repair-slave-equipment RechargeSkill, // recharge-skill @@ -148,7 +148,7 @@ public enum ItemTaskType : byte ItemTaskResurrectionInPlace, // item-task-resurrection-in-place TodayAssignmentSupplyItems, // today-assignment-supply-items ItemTaskBattleCoin, // item-task-battle-coin - GiveRewardItem, // give-reward-item + GiveRewardItem = 144, // give-reward-item ExchangeAapointFromCash, // exchange-aapoint-from-cash SpendItemFromChat, // spend-item-from-chat ItemTaskRemoveHeroReward, // = 143,// item-task-remove-hero-reward diff --git a/AAEmu.Game/Models/Game/Items/Containers/ItemContainer.cs b/AAEmu.Game/Models/Game/Items/Containers/ItemContainer.cs index 11d806e38d..7f0ac864ee 100644 --- a/AAEmu.Game/Models/Game/Items/Containers/ItemContainer.cs +++ b/AAEmu.Game/Models/Game/Items/Containers/ItemContainer.cs @@ -404,6 +404,7 @@ public bool AddOrMoveExistingItem(ItemTaskType taskType, Item item, int preferre if (sourceContainer != null && sourceContainer != this) { sourceContainer.Items.Remove(item); + sourceContainer.IsDirty = true; sourceContainer.UpdateFreeSlotCount(); if (sourceContainer.ContainerType != SlotType.MailAttachment) { @@ -450,6 +451,173 @@ public bool AddOrMoveExistingItem(ItemTaskType taskType, Item item, int preferre return itemTasks.Count + sourceItemTasks.Count > 0; } + /// + /// Adds an Item Object to this container and also updates source container, for new items like craft results, use AcquireDefaultItem instead + /// + /// + /// Item Object to add/move to this container + /// preferred slot to place this item in + /// Fails on Full Inventory or if target slot is invalid + public bool AddOrMoveExistingItem2(ItemTaskType taskType, Item item, int preferredSlot = -1) + { + if (item == null) + { + return false; + } + + var sourceContainer = item._holdingContainer; + var sourceSlot = (byte)item.Slot; + var sourceSlotType = item.SlotType; + + var currentPreferredSlotItem = GetItemBySlot(preferredSlot); + var newSlot = -1; + var canAddToSameSlot = false; + + // When adding wearables to equipment container, for the slot numbers if needed + if (this is EquipmentContainer && item is EquipItem _ && preferredSlot < 0) + { + var validSlots = EquipmentContainer.GetAllowedGearSlots(item.Template); + // find valid empty slot (if any), stop looking if it is the preferred slot + foreach (var vSlot in validSlots) + { + if (GetItemBySlot((int)vSlot) == null) + { + newSlot = (int)vSlot; + break; + } + } + } + + // Make sure the item is in container size's range + if ( + ContainerType == SlotType.Bag && item.Template.MaxCount > 1 && + currentPreferredSlotItem != null && + currentPreferredSlotItem.TemplateId == item.TemplateId && currentPreferredSlotItem.Grade == item.Grade && + item.Count + currentPreferredSlotItem.Count <= item.Template.MaxCount) + { + newSlot = preferredSlot; + canAddToSameSlot = true; + } + else + { + if (newSlot < 0) + { + newSlot = GetUnusedSlot(preferredSlot); + } + + if (newSlot < 0) + { + return false; // Inventory Full + } + } + + // Check if the newSlot fits + if (!CanAccept(item, newSlot)) + { + return false; + } + + var itemTasks = new List(); + var sourceItemTasks = new List(); + + if (canAddToSameSlot) + { + currentPreferredSlotItem.Count += item.Count; + if (ContainerType != SlotType.Invalid) + { + itemTasks.Add(new ItemCountUpdate(currentPreferredSlotItem, item.Count)); + } + } + else + { + item.SlotType = ContainerType; + item.Slot = newSlot; + item._holdingContainer = this; + item.OwnerId = OwnerId; + + Items.Insert(0, item); // insert at front for easy buyback handling + + UpdateFreeSlotCount(); + + // Note we use SlotType.None for things like the Item BuyBack Container. Make sure to manually handle the remove for these + if (ContainerType != SlotType.Invalid) + { + itemTasks.Add(new ItemAdd(item)); + } + + if (sourceContainer != this) + { + sourceContainer?.OnLeaveContainer(item, sourceContainer, sourceSlot); + OnEnterContainer(item, this, (byte)newSlot); + } + } + + // Item Tasks + if (sourceContainer?.ContainerType is not (SlotType.MailAttachment and SlotType.Auction)) + { + if (sourceContainer is not null && sourceContainer != this) + { + sourceContainer.Items.Remove(item); + sourceContainer.IsDirty = true; + sourceContainer.UpdateFreeSlotCount(); + if (sourceContainer.ContainerType != SlotType.MailAttachment || sourceContainer.ContainerType != SlotType.Auction) + { + sourceItemTasks.Add(new ItemRemoveSlot(item.Id, sourceSlotType, sourceSlot)); + } + } + } + + // We use Invalid when doing internals, don't send to client + if (taskType != ItemTaskType.Invalid) + { + if (itemTasks.Count > 0) + { + Owner?.SendPacket(new SCItemTaskSuccessPacket(taskType, itemTasks, new List())); + } + + if (sourceItemTasks.Count > 0) + { + sourceContainer?.Owner?.SendPacket(new SCItemTaskSuccessPacket(taskType, sourceItemTasks, new List())); + } + } + + ApplyBindRules(taskType); + + // Moved to the end of the method so that the item is already in the inventory + // Only trigger when moving between containers with different owners except for this being move to Mail container + //if ((sourceContainer != this) && (item.OwnerId != OwnerId) && (this.ContainerType != SlotType.MailAttachment)) + if (sourceContainer != this && (ContainerType != SlotType.MailAttachment || ContainerType != SlotType.Auction)) + { + Owner?.Inventory.OnAcquiredItem(item, item.Count); + } + else + // Got attachment from Mail + if (item.SlotType == SlotType.MailAttachment && ContainerType != SlotType.MailAttachment) + { + Owner?.Inventory.OnAcquiredItem(item, item.Count); + } + else + // Adding mail attachment + if (item.SlotType != SlotType.MailAttachment && ContainerType == SlotType.MailAttachment) + { + Owner?.Inventory.OnConsumedItem(item, item.Count); + } + else + // Got attachment from Auction + if (item.SlotType == SlotType.Auction && ContainerType != SlotType.Auction) + { + Owner?.Inventory.OnAcquiredItem(item, item.Count); + } + else + // Adding Auction attachment + if (item.SlotType != SlotType.Auction && ContainerType == SlotType.Auction) + { + Owner?.Inventory.OnConsumedItem(item, item.Count); + } + + return itemTasks.Count + sourceItemTasks.Count > 0; + } + /// /// Removes (and Destroys if needed) an item from the container /// diff --git a/AAEmu.Game/Models/Game/Mails/BaseMail.cs b/AAEmu.Game/Models/Game/Mails/BaseMail.cs index d198fb3952..df7f885bfb 100644 --- a/AAEmu.Game/Models/Game/Mails/BaseMail.cs +++ b/AAEmu.Game/Models/Game/Mails/BaseMail.cs @@ -4,7 +4,6 @@ using AAEmu.Game.Core.Managers.World; using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Items; -using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; diff --git a/AAEmu.Game/Models/Game/Mails/CommercialMail.cs b/AAEmu.Game/Models/Game/Mails/CommercialMail.cs index 128db3cf56..709c18caaa 100644 --- a/AAEmu.Game/Models/Game/Mails/CommercialMail.cs +++ b/AAEmu.Game/Models/Game/Mails/CommercialMail.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using AAEmu.Game.Core.Managers.World; +using AAEmu.Game.Core.Packets.G2C; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; using AAEmu.Game.Models.Game.Mails.Static; @@ -40,11 +41,13 @@ public CommercialMail(uint receiverId, string receiverName, string senderName, L _purchasedItemTitle = purchasedItemTitle; MailType = MailType.Charged; + Header.Status = MailStatus.Unpaid; Header.SenderId = (uint)SystemMailSenderKind.IngameShop; Header.SenderName = InGameCashShopSenderName; // Name changes depending on type of mail ReceiverName = receiverName; Header.ReceiverId = _receiverId; + Body.SendDate = DateTime.UtcNow; Body.RecvDate = DateTime.UtcNow; // These mails should always be instant } @@ -58,21 +61,41 @@ public void FinalizeMail() // If the player is exists, move it to their mail container first var targetCharacter = WorldManager.Instance.GetCharacter(_receiverName); if (targetCharacter != null) + { foreach (var item in Body.Attachments) - targetCharacter.Inventory.MailAttachments.AddOrMoveExistingItem(ItemTaskType.Invalid, item); + { + if (targetCharacter.Inventory.MailAttachments.AddOrMoveExistingItem(ItemTaskType.BuyItemIngameshop, item)) + { + // TODO здесь должно уменьшаться то, чем оплатили в магазине + //targetCharacter.SendPacket(new SCItemTaskSuccessPacket(ItemTaskType.BuyItemIngameshop, [], [])); + } + } + } // Title looks like it should be the item shop entry names (in multiple language?) // Title = "title('Rainbow Pumpkin Taffy|Rainbow Pumpkin Taffy|Rainbow Pumpkin Taffy|彩虹南瓜糖|Радужный марципан')"; - Title = "title('" + _purchasedItemTitle.Replace("'", "\\'") + "')"; - OpenDate = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc); // Always in the past + var purchasedItemTitle = _purchasedItemTitle.Replace("'", "\\'").Replace("(", "").Replace(")", ""); + Title = "title('" + + purchasedItemTitle + "|" + + purchasedItemTitle + "|" + + purchasedItemTitle + "|" + + purchasedItemTitle + "|" + + purchasedItemTitle + "')"; + OpenDate = new DateTime(1999, 12, 31, 0, 0, 0, DateTimeKind.Utc); // Always in the past // Not sure what all the body fields mean - var isPresent = (_isGift && (_senderName != string.Empty)) ? "true" : "false"; - var gifterName = (_isGift ? _senderName : ""); - var giftString = (_isGift ? "1" : "0"); - var refundString = (_isRefund ? "1" : "0"); + var isPresent = _isGift && _senderName != string.Empty ? "true" : "false"; + var gifterName = _isGift ? _senderName : ""; + var giftString = _isGift ? "1" : "0"; + var refundString = _isRefund ? "1" : "0"; var expireDateString = "2100,12,31,00,00,00"; - Body.Text = "body(" + isPresent + ",'" + gifterName + "','" + _purchasedItemTitle.Replace("'", "\\'") + "')" + + Body.Text = "body(" + isPresent + ",'" + gifterName + + "','" + + purchasedItemTitle + "|" + + purchasedItemTitle + "|" + + purchasedItemTitle + "|" + + purchasedItemTitle + "|" + + purchasedItemTitle + "', 4)" + "|gift:" + giftString + ";|refund:" + refundString + ";|limit:" + expireDateString + ";"; } } diff --git a/AAEmu.Game/Models/Game/Mails/CountUnreadMail.cs b/AAEmu.Game/Models/Game/Mails/CountUnreadMail.cs index 02f4183c9e..d3273d4645 100644 --- a/AAEmu.Game/Models/Game/Mails/CountUnreadMail.cs +++ b/AAEmu.Game/Models/Game/Mails/CountUnreadMail.cs @@ -1,5 +1,4 @@ using AAEmu.Commons.Network; -using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; @@ -53,7 +52,10 @@ public void UpdateReceived(MailType mailType, int amount) { TotalReceived += amount; } + + Logger.Debug($"UpdateReceived: TotalCommercialReceived={TotalCommercialReceived}, TotalMiaReceived={TotalMiaReceived}, TotalReceived={TotalReceived}"); } + public void UpdateUnreadReceived(MailType mailType, int amount) { if (mailType is MailType.Charged or MailType.Promotion) @@ -69,6 +71,13 @@ public void UpdateUnreadReceived(MailType mailType, int amount) { UnreadReceived += amount; } + Logger.Debug($"UpdateUnreadReceived: UnreadCommercialReceived={UnreadCommercialReceived}, UnreadMiaReceived={UnreadMiaReceived}, UnreadReceived={UnreadReceived}"); } + public void UpdateSend(int amount) + { + TotalSent += amount; + + Logger.Debug($"UpdateSend: TotalSent={TotalSent}"); + } } diff --git a/AAEmu.Game/Models/Game/Mails/MailBody.cs b/AAEmu.Game/Models/Game/Mails/MailBody.cs index f6e9e89c54..0ee026c630 100644 --- a/AAEmu.Game/Models/Game/Mails/MailBody.cs +++ b/AAEmu.Game/Models/Game/Mails/MailBody.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using AAEmu.Commons.Network; using AAEmu.Game.Models.Game.Items; -using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; diff --git a/AAEmu.Game/Models/Game/Mails/MailPlayerToPlayer.cs b/AAEmu.Game/Models/Game/Mails/MailPlayerToPlayer.cs index 5fbeef7480..921665b1d5 100644 --- a/AAEmu.Game/Models/Game/Mails/MailPlayerToPlayer.cs +++ b/AAEmu.Game/Models/Game/Mails/MailPlayerToPlayer.cs @@ -4,7 +4,6 @@ using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Items.Actions; -using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Models.Game.Mails; diff --git a/AAEmu.Game/Models/Game/Mails/Static/MailType.cs b/AAEmu.Game/Models/Game/Mails/Static/MailType.cs index b65773e9b4..543117b3ae 100644 --- a/AAEmu.Game/Models/Game/Mails/Static/MailType.cs +++ b/AAEmu.Game/Models/Game/Mails/Static/MailType.cs @@ -1,4 +1,4 @@ -namespace AAEmu.Game.Models.Game.Mails.Static; +namespace AAEmu.Game.Models.Game.Mails; public enum MailType : byte { diff --git a/AAEmu.Game/Models/Game/Skills/Effects/GainLootPackItemEffect.cs b/AAEmu.Game/Models/Game/Skills/Effects/GainLootPackItemEffect.cs index 7f0dbca188..ffb2b09eaf 100644 --- a/AAEmu.Game/Models/Game/Skills/Effects/GainLootPackItemEffect.cs +++ b/AAEmu.Game/Models/Game/Skills/Effects/GainLootPackItemEffect.cs @@ -33,6 +33,8 @@ public override void Apply(BaseUnit caster, SkillCaster casterObj, BaseUnit targ return; // Get Pack data + Logger.Debug($"GainLootPackItemEffect: LootPackId={LootPackId}"); + var pack = LootGameData.Instance.GetPack(LootPackId); if (pack == null || pack.Loots.Count <= 0) return; diff --git a/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/FishingLoot.cs b/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/FishingLoot.cs index e3101ea24b..1a20b24d1f 100644 --- a/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/FishingLoot.cs +++ b/AAEmu.Game/Models/Game/Skills/Effects/SpecialEffects/FishingLoot.cs @@ -40,6 +40,8 @@ public override void Execute(BaseUnit caster, var lootTableId = target.Transform.World.Position.Z > 101 ? zoneGroup.FishingLandLootPackId : zoneGroup.FishingSeaLootPackId; + Logger.Debug($"FishingLoot: lootTableId={lootTableId}"); + var pack = LootGameData.Instance.GetPack(lootTableId); if (pack == null || pack.Loots.Count <= 0) diff --git a/AAEmu.Game/Models/Tasks/CashShop/CashShopBuyTask.cs b/AAEmu.Game/Models/Tasks/CashShop/CashShopBuyTask.cs index d8eb7557ec..8e21ebb908 100644 --- a/AAEmu.Game/Models/Tasks/CashShop/CashShopBuyTask.cs +++ b/AAEmu.Game/Models/Tasks/CashShop/CashShopBuyTask.cs @@ -3,7 +3,6 @@ using AAEmu.Game.Core.Managers; using AAEmu.Game.Core.Packets.G2C; -using AAEmu.Game.Models.Game; using AAEmu.Game.Models.Game.CashShop; using AAEmu.Game.Models.Game.Char; using AAEmu.Game.Models.Game.Items; @@ -252,7 +251,7 @@ public override void Execute() case CashShopCurrencyType.Loyalty: if (beforeBuyAccountDetails.Loyalty < sku.Price) Logger.Error($"Sale validation failed for {_buyer.Name}, {sku.Currency} x {sku.Price}"); - AccountManager.Instance.AddLoyalty(_buyer.AccountId, (int)(sku.Price * -1)); + AccountManager.Instance.AddLoyalty(_buyer.AccountId, (int)-sku.Price); break; case CashShopCurrencyType.Coins: if (!_buyer.SubtractMoney(SlotType.Bag, (int)sku.Price, ItemTaskType.StoreBuy)) @@ -288,10 +287,12 @@ public override void Execute() entriesSold++; Logger.Info($"ICSBuyGood {_buyer.Name} -> {_targetPlayer.Name} - {useName} x {sku.ItemCount}, SKU:{sku.Sku}"); - if (!CashShopManager.Instance.LogSale(_buyer.AccountId, _buyer.Id, _targetPlayer.AccountId, - _targetPlayer.Id, DateTime.UtcNow, shopItem.ShopId, sku.Sku, (sku.DiscountPrice > 0 ? sku.DiscountPrice : sku.Price), sku.Currency, string.Empty)) - Logger.Error( - $"ICSBuyGood {_buyer.Name} -> {_targetPlayer.Name} - {useName} x {sku.ItemCount}, SKU:{sku.Sku}, save failed!"); + if (!CashShopManager.Instance.LogSale(_buyer.AccountId, _buyer.Id, _targetPlayer.AccountId, _targetPlayer.Id, DateTime.UtcNow, shopItem.ShopId, sku.Sku, + sku.DiscountPrice > 0 + ? sku.DiscountPrice + : sku.Price, + sku.Currency, string.Empty)) + Logger.Error($"ICSBuyGood {_buyer.Name} -> {_targetPlayer.Name} - {useName} x {sku.ItemCount}, SKU:{sku.Sku}, save failed!"); } if (entriesSold > 0) diff --git a/AAEmu.Game/Scripts/Commands/TestMails.cs b/AAEmu.Game/Scripts/Commands/TestMails.cs index 1d46fac4ce..ba12d69c6a 100644 --- a/AAEmu.Game/Scripts/Commands/TestMails.cs +++ b/AAEmu.Game/Scripts/Commands/TestMails.cs @@ -6,7 +6,6 @@ using AAEmu.Game.Models.Game.Chat; using AAEmu.Game.Models.Game.Items; using AAEmu.Game.Models.Game.Mails; -using AAEmu.Game.Models.Game.Mails.Static; using AAEmu.Game.Utils.Scripts; namespace AAEmu.Game.Scripts.Commands; diff --git a/AAEmu.Game/Services/WebApi/Models/SendMailRequest.cs b/AAEmu.Game/Services/WebApi/Models/SendMailRequest.cs index c8e5c2f9e3..99d63c4875 100644 --- a/AAEmu.Game/Services/WebApi/Models/SendMailRequest.cs +++ b/AAEmu.Game/Services/WebApi/Models/SendMailRequest.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using AAEmu.Game.Models.Game.Mails; -using AAEmu.Game.Models.Game.Mails.Static; namespace AAEmu.Game.Services.WebApi.Models; diff --git a/SQL/aaemu_game.sql b/SQL/aaemu_game.sql index e442737ef9..f0aba8aa5c 100644 --- a/SQL/aaemu_game.sql +++ b/SQL/aaemu_game.sql @@ -26,7 +26,7 @@ CREATE TABLE `abilities` ( `exp` int NOT NULL, `owner` int UNSIGNED NOT NULL, PRIMARY KEY (`id`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Skillsets Exp' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Skillsets Exp' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for accounts @@ -44,7 +44,7 @@ CREATE TABLE `accounts` ( `last_credits_tick` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `last_loyalty_tick` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`account_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Account specific values not related to login' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Account specific values not related to login' ROW_FORMAT = Dynamic; -- ---------------------------- -- Triggers structure for table accounts @@ -70,7 +70,7 @@ CREATE TABLE `actabilities` ( `step` tinyint UNSIGNED NOT NULL DEFAULT 0, `owner` int UNSIGNED NOT NULL, PRIMARY KEY (`owner`, `id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Vocations' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Vocations' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for appellations @@ -81,7 +81,7 @@ CREATE TABLE `appellations` ( `active` tinyint(1) NOT NULL DEFAULT 0, `owner` int UNSIGNED NOT NULL, PRIMARY KEY (`id`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Earned titles' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Earned titles' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for attendances @@ -93,7 +93,7 @@ CREATE TABLE `attendances` ( `account_attendance` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `accept` tinyint(1) NOT NULL, PRIMARY KEY (`id`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ---------------------------------- -- Table structure for auction_house @@ -103,22 +103,23 @@ CREATE TABLE `auction_house` ( `id` bigint NOT NULL AUTO_INCREMENT, `duration` tinyint NOT NULL, `item_id` bigint NOT NULL, - `end_time` datetime NOT NULL, + `post_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Time when the auction item was put up for sale (in UTC)', + `end_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Time when the sale period ends (in UTC)', `world_id` tinyint NOT NULL, `client_id` int NOT NULL, - `client_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `client_name` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `start_money` int NOT NULL, `direct_money` int NOT NULL, `charge_percent` int NOT NULL, `bid_world_id` int NOT NULL, `bidder_id` int NOT NULL, - `bidder_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `bidder_name` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `bid_money` int NOT NULL, `extra` int NOT NULL, `min_stack` int NOT NULL, `max_stack` int NOT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Listed AH Items' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Listed AH Items' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for auction_solds_data @@ -151,13 +152,13 @@ CREATE TABLE `audit_ics_sales` ( `sku` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'SKU of the sold item', `sale_cost` int NOT NULL DEFAULT 0 COMMENT 'Amount this item was sold for', `sale_currency` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Which currency was used', - `description` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT 'Added description of this transaction', + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Added description of this transaction', PRIMARY KEY (`id`) USING BTREE, INDEX `buyer_account`(`buyer_account`) USING BTREE, INDEX `buyer_char`(`buyer_char`) USING BTREE, INDEX `target_account`(`target_account`) USING BTREE, INDEX `target_char`(`target_char`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Sales history for the ICS' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Sales history for the ICS' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for blocked @@ -167,7 +168,7 @@ CREATE TABLE `blocked` ( `owner` int NOT NULL, `blocked_id` int NOT NULL, PRIMARY KEY (`owner`, `blocked_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for characters @@ -176,7 +177,7 @@ DROP TABLE IF EXISTS `characters`; CREATE TABLE `characters` ( `id` int UNSIGNED NOT NULL, `account_id` int UNSIGNED NOT NULL, - `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `access_level` int UNSIGNED NOT NULL DEFAULT 0, `race` tinyint NOT NULL, `gender` tinyint(1) NOT NULL, @@ -199,7 +200,7 @@ CREATE TABLE `characters` ( `pitch` float NOT NULL DEFAULT 0, `roll` float NOT NULL DEFAULT 0, `faction_id` int UNSIGNED NOT NULL, - `faction_name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `faction_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `expedition_id` int NOT NULL, `family` int UNSIGNED NOT NULL, `dead_count` mediumint UNSIGNED NOT NULL, @@ -234,7 +235,7 @@ CREATE TABLE `characters` ( `return_district` int NOT NULL DEFAULT 0, `online_time` int NOT NULL DEFAULT 0 COMMENT 'Time that the character has been online', PRIMARY KEY (`id`, `account_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Basic player character data' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Basic player character data' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for completed_quests @@ -245,7 +246,7 @@ CREATE TABLE `completed_quests` ( `data` tinyblob NOT NULL, `owner` int UNSIGNED NOT NULL, PRIMARY KEY (`id`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Quests marked as completed for character' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Quests marked as completed for character' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for doodads @@ -276,7 +277,7 @@ CREATE TABLE `doodads` ( `data` int NOT NULL DEFAULT 0 COMMENT 'Doodad specific data', `farm_type` int NOT NULL DEFAULT 0 COMMENT 'farm type for Public Farm', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Persistent doodads (e.g. tradepacks, furniture)' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Persistent doodads (e.g. tradepacks, furniture)' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for expedition_applicants @@ -285,12 +286,12 @@ DROP TABLE IF EXISTS `expedition_applicants`; CREATE TABLE `expedition_applicants` ( `expedition_id` int NOT NULL, `character_id` int NOT NULL, - `character_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `character_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `character_level` tinyint(1) NOT NULL, - `memo` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `memo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `reg_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', PRIMARY KEY (`expedition_id`, `character_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for expedition_members @@ -299,16 +300,16 @@ DROP TABLE IF EXISTS `expedition_members`; CREATE TABLE `expedition_members` ( `character_id` int NOT NULL, `expedition_id` int NOT NULL, - `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `level` tinyint UNSIGNED NOT NULL, `role` tinyint UNSIGNED NOT NULL, `last_leave_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `ability1` tinyint UNSIGNED NOT NULL, `ability2` tinyint UNSIGNED NOT NULL, `ability3` tinyint UNSIGNED NOT NULL, - `memo` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `memo` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, PRIMARY KEY (`character_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Guild members' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Guild members' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for expedition_recruitments @@ -316,17 +317,17 @@ CREATE TABLE `expedition_members` ( DROP TABLE IF EXISTS `expedition_recruitments`; CREATE TABLE `expedition_recruitments` ( `expedition_id` int NOT NULL, - `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `level` int NULL DEFAULT NULL, - `owner_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, - `introduce` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `owner_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `introduce` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `reg_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `end_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `member_count` int NULL DEFAULT NULL, `interest` int NULL DEFAULT NULL, `apply` tinyint(1) NOT NULL, PRIMARY KEY (`expedition_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Guild recruitments' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Guild recruitments' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for expedition_role_policies @@ -335,7 +336,7 @@ DROP TABLE IF EXISTS `expedition_role_policies`; CREATE TABLE `expedition_role_policies` ( `expedition_id` int NOT NULL, `role` tinyint UNSIGNED NOT NULL, - `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `dominion_declare` tinyint(1) NOT NULL, `invite` tinyint(1) NOT NULL, `expel` tinyint(1) NOT NULL, @@ -346,7 +347,7 @@ CREATE TABLE `expedition_role_policies` ( `siege_master` tinyint(1) NOT NULL, `join_siege` tinyint(1) NOT NULL, PRIMARY KEY (`expedition_id`, `role`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Guild role settings' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Guild role settings' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for expeditions @@ -355,8 +356,8 @@ DROP TABLE IF EXISTS `expeditions`; CREATE TABLE `expeditions` ( `id` int NOT NULL, `owner` int NOT NULL DEFAULT 0, - `owner_name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, - `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `owner_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `mother` int NOT NULL DEFAULT 0, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `level` int NOT NULL DEFAULT 0, @@ -367,13 +368,13 @@ CREATE TABLE `expeditions` ( `last_exp_update_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `is_level_update` tinyint(1) NOT NULL DEFAULT 0, `interest` int NOT NULL DEFAULT 0, - `motd_title` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, - `motd_content` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `motd_title` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `motd_content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `win` int NOT NULL DEFAULT 0, `lose` int NOT NULL DEFAULT 0, `draw` int NOT NULL DEFAULT 0, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Guilds' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Guilds' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for family_members @@ -382,11 +383,11 @@ DROP TABLE IF EXISTS `family_members`; CREATE TABLE `family_members` ( `character_id` int NOT NULL, `family_id` int NOT NULL, - `name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `name` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `role` tinyint(1) NOT NULL DEFAULT 0, - `title` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `title` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, PRIMARY KEY (`family_id`, `character_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Family members' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Family members' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for friends @@ -397,7 +398,7 @@ CREATE TABLE `friends` ( `friend_id` int NOT NULL, `owner` int NOT NULL, PRIMARY KEY (`id`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Friendslist' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Friendslist' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for housings @@ -409,7 +410,7 @@ CREATE TABLE `housings` ( `owner` int UNSIGNED NOT NULL, `co_owner` int UNSIGNED NOT NULL, `template_id` int UNSIGNED NOT NULL, - `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `x` float NOT NULL, `y` float NOT NULL, `z` float NOT NULL, @@ -426,7 +427,7 @@ CREATE TABLE `housings` ( `sell_price` bigint NOT NULL DEFAULT 0, `allow_recover` tinyint UNSIGNED NOT NULL DEFAULT 1, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Player buildings' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Player buildings' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for ics_menu @@ -439,7 +440,7 @@ CREATE TABLE `ics_menu` ( `tab_pos` int NOT NULL DEFAULT 0 COMMENT 'Used to change display order', `shop_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Id of the item group for sale (shop item)', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 100 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Contains what item will be displayed on which tab' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 100 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Contains what item will be displayed on which tab' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for ics_shop_items @@ -448,7 +449,7 @@ DROP TABLE IF EXISTS `ics_shop_items`; CREATE TABLE `ics_shop_items` ( `shop_id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'SKU item id', `display_item_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Item who\'s icon to use for displaying in the shop, leave 0 for first item in the group', - `name` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT 'Can be used to override the name in the shop', + `name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT 'Can be used to override the name in the shop', `limited_type` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Enables limited stock mode if non-zero, Account(1), Chracter(2)', `limited_stock_max` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Number of items left in stock for this SKU if limited stock is enabled', `level_min` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Minimum level to buy the item (does not show on UI)', @@ -462,7 +463,7 @@ CREATE TABLE `ics_shop_items` ( `shop_buttons` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT 'All (0), NoCart (1), NoGift (2), OnlyBuy (3)', `remaining` int NOT NULL DEFAULT -1 COMMENT 'Number of items remaining, only for tab 1-1 (limited)', PRIMARY KEY (`shop_id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 2000000 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Possible Item listings that are for sale' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 2000000 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Possible Item listings that are for sale' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for ics_skus @@ -485,7 +486,7 @@ CREATE TABLE `ics_skus` ( `bonus_item_count` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Amount of bonus items included', `pay_item_type` int UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (`sku`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1000000 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Has the actual sales items for the details' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 1000000 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Has the actual sales items for the details' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for item_containers @@ -493,13 +494,13 @@ CREATE TABLE `ics_skus` ( DROP TABLE IF EXISTS `item_containers`; CREATE TABLE `item_containers` ( `container_id` int UNSIGNED NOT NULL, - `container_type` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'ItemContainer' COMMENT 'Partial Container Class Name', + `container_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'ItemContainer' COMMENT 'Partial Container Class Name', `slot_type` int NOT NULL DEFAULT 0 COMMENT 'Internal Container Type', `container_size` int NOT NULL DEFAULT 50 COMMENT 'Maximum Container Size', `owner_id` int UNSIGNED NOT NULL COMMENT 'Owning Character Id', `mate_id` int UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Owning Mate Id', PRIMARY KEY (`container_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for items @@ -507,7 +508,7 @@ CREATE TABLE `item_containers` ( DROP TABLE IF EXISTS `items`; CREATE TABLE `items` ( `id` bigint UNSIGNED NOT NULL, - `type` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `template_id` int UNSIGNED NOT NULL, `container_id` int UNSIGNED NOT NULL DEFAULT 0, `slot_type` int NOT NULL DEFAULT 0 COMMENT 'Internal Container Type', @@ -529,7 +530,7 @@ CREATE TABLE `items` ( `charge_count` int NOT NULL DEFAULT 0 COMMENT 'Number of charges left', PRIMARY KEY (`id`) USING BTREE, INDEX `owner`(`owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'All items' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'All items' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for mails @@ -539,13 +540,13 @@ CREATE TABLE `mails` ( `id` int NOT NULL, `type` int NOT NULL, `status` int NOT NULL, - `title` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, - `text` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `title` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `sender_id` int NOT NULL DEFAULT 0, - `sender_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `sender_name` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `attachment_count` int NOT NULL DEFAULT 0, `receiver_id` int NOT NULL DEFAULT 0, - `receiver_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `receiver_name` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `open_date` datetime NOT NULL, `send_date` datetime NOT NULL, `received_date` datetime NOT NULL, @@ -565,7 +566,7 @@ CREATE TABLE `mails` ( `attachment8` bigint NOT NULL DEFAULT 0, `attachment9` bigint NOT NULL DEFAULT 0, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'In-game mails' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'In-game mails' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for mates @@ -574,7 +575,7 @@ DROP TABLE IF EXISTS `mates`; CREATE TABLE `mates` ( `id` int UNSIGNED NOT NULL, `item_id` bigint UNSIGNED NOT NULL, - `name` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `xp` int NOT NULL, `level` tinyint NOT NULL, `mileage` int NOT NULL, @@ -584,7 +585,7 @@ CREATE TABLE `mates` ( `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`, `item_id`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Player mounts and pets' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Player mounts and pets' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for music @@ -593,21 +594,21 @@ DROP TABLE IF EXISTS `music`; CREATE TABLE `music` ( `id` int NOT NULL AUTO_INCREMENT, `author` int NOT NULL COMMENT 'PlayerId', - `title` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, - `song` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT 'Song MML', + `title` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `song` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Song MML', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'User Created Content (music)' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'User Created Content (music)' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for options -- ---------------------------- DROP TABLE IF EXISTS `options`; CREATE TABLE `options` ( - `key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, - `value` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `owner` int UNSIGNED NOT NULL, PRIMARY KEY (`key`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Settings that the client stores on the server' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Settings that the client stores on the server' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for portal_book_coords @@ -615,7 +616,7 @@ CREATE TABLE `options` ( DROP TABLE IF EXISTS `portal_book_coords`; CREATE TABLE `portal_book_coords` ( `id` int NOT NULL, - `name` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `x` int NULL DEFAULT 0, `y` int NULL DEFAULT 0, `z` int NULL DEFAULT 0, @@ -624,7 +625,7 @@ CREATE TABLE `portal_book_coords` ( `sub_zone_id` int NULL DEFAULT 0, `owner` int NOT NULL, PRIMARY KEY (`id`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Recorded house portals in the portal book' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Recorded house portals in the portal book' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for portal_visited_district @@ -635,7 +636,7 @@ CREATE TABLE `portal_visited_district` ( `subzone` int NOT NULL, `owner` int NOT NULL, PRIMARY KEY (`id`, `subzone`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'List of visited area for the portal book' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'List of visited area for the portal book' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for quests @@ -648,7 +649,7 @@ CREATE TABLE `quests` ( `status` tinyint NOT NULL, `owner` int UNSIGNED NOT NULL, PRIMARY KEY (`id`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Currently open quests' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Currently open quests' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for resident_members @@ -657,12 +658,12 @@ DROP TABLE IF EXISTS `resident_members`; CREATE TABLE `resident_members` ( `id` int NOT NULL, `resident_id` int NOT NULL, - `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `level` tinyint(1) NOT NULL, `family` int NULL DEFAULT NULL, `service_point` int NULL DEFAULT NULL, PRIMARY KEY (`id`, `resident_id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for residents @@ -677,7 +678,7 @@ CREATE TABLE `residents` ( `zone_point` int NULL DEFAULT NULL, `charge` datetime NOT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 30 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 30 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for skills @@ -686,10 +687,10 @@ DROP TABLE IF EXISTS `skills`; CREATE TABLE `skills` ( `id` int UNSIGNED NOT NULL, `level` tinyint NOT NULL, - `type` enum('Skill','Buff') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `type` enum('Skill','Buff') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `owner` int UNSIGNED NOT NULL, PRIMARY KEY (`id`, `owner`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Learned character skills' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Learned character skills' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for slaves @@ -700,7 +701,7 @@ CREATE TABLE `slaves` ( `item_id` int UNSIGNED NULL DEFAULT NULL COMMENT 'Item that is used to summon this vehicle', `template_id` int UNSIGNED NULL DEFAULT NULL COMMENT 'Slave template Id of this vehicle', `attach_point` int NULL DEFAULT NULL COMMENT 'Binding point Id', - `name` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL, + `name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL, `owner_type` int UNSIGNED NULL DEFAULT 0 COMMENT 'Parent unit type', `owner_id` int UNSIGNED NULL DEFAULT 0 COMMENT 'Parent unit DB Id', `summoner` int UNSIGNED NULL DEFAULT NULL COMMENT 'Owning player', @@ -712,7 +713,7 @@ CREATE TABLE `slaves` ( `y` float NULL DEFAULT NULL, `z` float NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'Player vehicles summons' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Player vehicles summons' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for uccs @@ -736,7 +737,7 @@ CREATE TABLE `uccs` ( `color3B` int UNSIGNED NOT NULL, `modified` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'User Created Content (crests)' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'User Created Content (crests)' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for divine_clock diff --git a/SQL/updates/2024-10-30_aaemu_game_auction_house_update.sql b/SQL/updates/2024-10-30_aaemu_game_auction_house_update.sql new file mode 100644 index 0000000000..11db89cd69 --- /dev/null +++ b/SQL/updates/2024-10-30_aaemu_game_auction_house_update.sql @@ -0,0 +1,2 @@ +ALTER TABLE `auction_house` +ADD COLUMN `post_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Time when the auction item was put up for sale (in UTC)' AFTER `item_id`; \ No newline at end of file From 9538482296a9c1b7dbe0aaa8892991fcff007994 Mon Sep 17 00:00:00 2001 From: PulloutRequest Date: Thu, 9 Apr 2026 15:11:15 +0000 Subject: [PATCH 3/3] NPC now properly show quest markers and quests can be taken and turned in --- AAEmu.Game/Core/Packets/G2C/SCTowerConfigPacket.cs | 2 +- AAEmu.Game/Core/Packets/Proxy/FinishStatePacket.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AAEmu.Game/Core/Packets/G2C/SCTowerConfigPacket.cs b/AAEmu.Game/Core/Packets/G2C/SCTowerConfigPacket.cs index 159a0923a6..0b408afaef 100644 --- a/AAEmu.Game/Core/Packets/G2C/SCTowerConfigPacket.cs +++ b/AAEmu.Game/Core/Packets/G2C/SCTowerConfigPacket.cs @@ -19,7 +19,7 @@ public SCTowerConfigPacket() : base(SCOffsets.SCTowerConfigPacket, 5) _unk2 = 0; _unk3 = 1; _msg1 = "tower_def"; - _msg2 = "tower_kraken_newserver"; + _msg2 = "TowerDef_Kraken_newserver"; } public override PacketStream Write(PacketStream stream) diff --git a/AAEmu.Game/Core/Packets/Proxy/FinishStatePacket.cs b/AAEmu.Game/Core/Packets/Proxy/FinishStatePacket.cs index fa3cd1edd6..19f7aa5928 100644 --- a/AAEmu.Game/Core/Packets/Proxy/FinishStatePacket.cs +++ b/AAEmu.Game/Core/Packets/Proxy/FinishStatePacket.cs @@ -35,7 +35,7 @@ public override void Read(PacketStream stream) Connection.SendPacket(new SetGameTypePacket(levelname, 0, 1)); // TODO - level Connection.SendPacket(new SCInitialConfigPacket()); // added in 5.0.7.0 - //Connection.SendPacket(new SCTowerConfigPacket()); + Connection.SendPacket(new SCTowerConfigPacket()); // Test URLs // Original Trion values // Client treats these as folders and will add a trailing slash (/) with whatever it needs