From 82eb6e808efceb3c6b39e48bc7134e6a830f2487 Mon Sep 17 00:00:00 2001 From: SylvaniaCore deploy Date: Sat, 22 Aug 2026 14:47:59 +0200 Subject: [PATCH] Nouveau type de condition : specialisation du joueur (53) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit « Arretez Guldan ! » etait proposee en double par Maiev. Les quetes 38723 et 40253 partagent titre, prerequis, tri, et sont ouvertes a toutes les races : rien ne les departageait. Ce ne sont pas des variantes Horde/Alliance malgre le nom des constantes QUEST_STOP_GULDAN_H/_A — le meme fichier les nomme correctement plus bas DMG_SPEC et TANK_SPEC. Ce sont des jumelles de specialisation. Le gestionnaire de conditions navait aucun moyen de tester la specialisation. Le contournement par un sort caracteristique netait pas tenable : les sorts de specialisation ne sont quasiment pas enseignes sur ce serveur, les trois Chasseurs de demons existants ne connaissent que Morsure de demon et celui de niveau 98 na pas sa Metamorphose. Une condition batie dessus aurait masque les DEUX quetes. CONDITION_SPECIALIZATION lit Player::GetPrimarySpecialization() et valide la valeur contre ChrSpecialization.db2 au chargement. Formulation retenue en base : la quete Vengeance exige la spe Vengeance, la quete Devastation exige de NE PAS etre Vengeance. Il y a ainsi toujours exactement une quete proposee, meme si la specialisation vaut zero — un doublon agace, zero quete bloque. Reutilisable : le serveur compte 1488 paires de quetes homonymes partageant prerequis et races. --- .../quetes_jumelles_specialisation.sql | 48 +++++++++++++++++++ src/server/game/Conditions/ConditionMgr.cpp | 19 ++++++++ src/server/game/Conditions/ConditionMgr.h | 1 + 3 files changed, 68 insertions(+) create mode 100644 sql/sylvania/quetes_jumelles_specialisation.sql diff --git a/sql/sylvania/quetes_jumelles_specialisation.sql b/sql/sylvania/quetes_jumelles_specialisation.sql new file mode 100644 index 0000000..5f7a235 --- /dev/null +++ b/sql/sylvania/quetes_jumelles_specialisation.sql @@ -0,0 +1,48 @@ +-- ===================================================================== +-- « Arrêtez Gul'dan ! » proposée en double — quêtes jumelles de spé +-- +-- Signalé en jeu, à répétition : Maiev propose DEUX fois la même quête. +-- +-- 38723 et 40253 portent le même titre, le même prérequis (38690), le +-- même tri (-407) et sont ouvertes à TOUTES les races +-- (AllowableRaces = 0xFFFFFFFFFFFFFFFF). Rien, absolument rien dans les +-- données ne les départageait : les deux étaient donc offertes ensemble. +-- +-- Ce ne sont PAS des variantes Horde / Alliance, malgré le nom trompeur +-- des constantes du core (QUEST_STOP_GULDAN_H / _A). Le même fichier les +-- nomme correctement plus bas : +-- QUEST_STOP_GULDAN_DMG_SPEC = 38723, -> Dévastation +-- QUEST_STOP_GULDAN_TANK_SPEC = 40253, -> Vengeance +-- Ce sont des jumelles de SPÉCIALISATION. +-- +-- Pourquoi une modification du moteur a été nécessaire +-- Le gestionnaire de conditions n'avait aucun moyen de tester la +-- spécialisation d'un joueur. Le contournement évident — tester un sort +-- caractéristique de chaque spé — ne tient pas debout ici : les sorts de +-- spécialisation ne sont quasiment pas enseignés sur ce serveur (les +-- trois Chasseurs de démons existants ne connaissent que Morsure de +-- démon ; celui de niveau 98 n'a même pas sa Métamorphose). Une +-- condition bâtie là-dessus aurait masqué les DEUX quêtes. +-- CONDITION_SPECIALIZATION (53) a donc été ajoutée au core, et elle lit +-- directement `Player::GetPrimarySpecialization()`. +-- +-- Choix de formulation : la quête Vengeance exige la spé Vengeance ; la +-- quête Dévastation exige de NE PAS être Vengeance, au lieu d'exiger +-- Dévastation. Ainsi il y a TOUJOURS exactement une quête proposée, même +-- pour un personnage dont la spécialisation serait à zéro ou inattendue. +-- Un doublon est agaçant ; zéro quête serait bloquant. +-- +-- Ce n'est pas un cas isolé : le serveur compte 1488 paires de quêtes +-- homonymes partageant prérequis et races. La nouvelle condition servira +-- ailleurs. +-- +-- Rechargeable à chaud : reload conditions (après redémarrage du binaire) +-- ===================================================================== + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=19 AND `SourceEntry` IN (38723,40253); +INSERT INTO `conditions` + (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`, + `ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`, + `NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(19,0,40253,0,0, 53,0,581,0,0, 0,0,0,'', 'Arretez Guldan ! version Vengeance - uniquement si spe Vengeance (581)'), +(19,0,38723,0,0, 53,0,581,0,0, 1,0,0,'', 'Arretez Guldan ! version Devastation - uniquement si spe PAS Vengeance'); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index db2b8a7..f76736f 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -126,6 +126,7 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND { "Aura stack amount", true, true, false }, { "Object Entry or Guid", true, true, true }, { "Object TypeMask", true, false, false }, + { "Specialization", true, false, false }, }; // Checks if object meets the condition @@ -341,6 +342,12 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const condMeets = object->isType(ConditionValue1); break; } + case CONDITION_SPECIALIZATION: + { + if (Player* player = object->ToPlayer()) + condMeets = player->GetPrimarySpecialization() == ConditionValue1; + break; + } case CONDITION_RELATION_TO: { if (WorldObject* toObject = sourceInfo.mConditionTargets[ConditionValue1]) @@ -656,6 +663,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() const if (ConditionValue1 & TYPEMASK_AREATRIGGER) mask |= GRID_MAP_TYPE_MASK_AREATRIGGER; break; + case CONDITION_SPECIALIZATION: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; case CONDITION_RELATION_TO: mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; break; @@ -2164,6 +2174,15 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const } break; } + case CONDITION_SPECIALIZATION: + { + if (!sChrSpecializationStore.LookupEntry(cond->ConditionValue1)) + { + TC_LOG_ERROR("sql.sql", "%s has non existing specialization (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); + return false; + } + break; + } case CONDITION_RELATION_TO: { if (cond->ConditionValue1 >= cond->GetMaxAvailableConditionTargets()) diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 5b0b4ad..7db4311 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -104,6 +104,7 @@ enum ConditionTypes CONDITION_AURA_STACK_AMOUNT = 50, // spell_id stack 0 true if player (or target) has aura of spell_id with stack amount CONDITION_OBJECT_ENTRY_GUID = 51, // TypeID entry guid true if object is type TypeID and the entry is 0 or matches entry of the object or matches guid of the object CONDITION_TYPE_MASK = 52, // TypeMask 0 0 true if object is type object's TypeMask matches provided TypeMask + CONDITION_SPECIALIZATION = 53, // specId 0 0 true if player's primary specialization is specId (ChrSpecialization) CONDITION_MAX };