Skip to content

Commit

Permalink
[10621] Add new field RequiredClasses for quest_template
Browse files Browse the repository at this point in the history
* SkillOrClass is converted to RequiredSkill (and then field can contain skill id only)
* Field ZoneOrSort has no longer a function in quest requirement, and RequiredClasses must be used instead where class limits are expected.

To restrict a quest to one class or more, use bitmask of class in RequiredClasses. RequiredSkill works like before.

Signed-off-by: NoFantasy <nofantasy@nf.no>
  • Loading branch information
NoFantasy committed Oct 18, 2010
1 parent 93b2f8f commit a946ebc
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 166 deletions.
5 changes: 3 additions & 2 deletions sql/mangos.sql
Expand Up @@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0',
`required_10604_01_mangos_spell_proc_event` bit(1) default NULL
`required_10621_01_mangos_quest_template` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';

--
Expand Down Expand Up @@ -13894,11 +13894,12 @@ CREATE TABLE `quest_template` (
`entry` mediumint(8) unsigned NOT NULL default '0',
`Method` tinyint(3) unsigned NOT NULL default '2',
`ZoneOrSort` smallint(6) NOT NULL default '0',
`SkillOrClass` smallint(6) NOT NULL default '0',
`MinLevel` tinyint(3) unsigned NOT NULL default '0',
`QuestLevel` smallint(6) NOT NULL default '0',
`Type` smallint(5) unsigned NOT NULL default '0',
`RequiredClasses` smallint(5) unsigned NOT NULL default '0',
`RequiredRaces` smallint(5) unsigned NOT NULL default '0',
`RequiredSkill` smallint(5) unsigned NOT NULL default '0',
`RequiredSkillValue` smallint(5) unsigned NOT NULL default '0',
`RepObjectiveFaction` smallint(5) unsigned NOT NULL default '0',
`RepObjectiveValue` mediumint(9) NOT NULL default '0',
Expand Down
40 changes: 40 additions & 0 deletions sql/updates/10621_01_mangos_quest_template.sql
@@ -0,0 +1,40 @@
ALTER TABLE db_version CHANGE COLUMN required_10604_01_mangos_spell_proc_event required_10621_01_mangos_quest_template bit;

ALTER TABLE quest_template ADD COLUMN RequiredClasses smallint(5) unsigned NOT NULL default '0' AFTER Type;

UPDATE quest_template
SET RequiredClasses = RequiredClasses|
CASE SkillOrClass
WHEN -1 THEN 1 -- warrior
WHEN -2 THEN 2 -- paladin
WHEN -3 THEN 4 -- hunter
WHEN -4 THEN 8 -- rogue
WHEN -5 THEN 16 -- priest
WHEN -6 THEN 32 -- dk
WHEN -7 THEN 64 -- shaman
WHEN -8 THEN 128 -- mage
WHEN -9 THEN 256 -- warlock
WHEN -11 THEN 1024 -- druid
ELSE 0
END
WHERE SkillOrClass < 0;

UPDATE quest_template
SET RequiredClasses = RequiredClasses|
CASE ZoneOrSort
WHEN -81 THEN 1 -- warrior
WHEN -141 THEN 2 -- paladin
WHEN -261 THEN 4 -- hunter
WHEN -162 THEN 8 -- rogue
WHEN -262 THEN 16 -- priest
WHEN -372 THEN 32 -- dk
WHEN -82 THEN 64 -- shaman
WHEN -161 THEN 128 -- mage
WHEN -61 THEN 256 -- warlock
WHEN -263 THEN 1024 -- druid
ELSE 0
END
WHERE ZoneOrSort < 0;

UPDATE quest_template SET SkillOrClass=0 WHERE SkillOrClass<0;
ALTER TABLE quest_template CHANGE COLUMN SkillOrClass RequiredSkill smallint(5) unsigned NOT NULL default '0' AFTER RequiredRaces;
2 changes: 2 additions & 0 deletions sql/updates/Makefile.am
Expand Up @@ -106,6 +106,7 @@ pkgdata_DATA = \
10568_01_characters_character_tutorial.sql \
10582_01_mangos_spell_proc_event.sql \
10604_01_mangos_spell_proc_event.sql \
10621_01_mangos_quest_template.sql \
README

## Additional files to include when running 'make dist'
Expand Down Expand Up @@ -192,4 +193,5 @@ EXTRA_DIST = \
10568_01_characters_character_tutorial.sql \
10582_01_mangos_spell_proc_event.sql \
10604_01_mangos_spell_proc_event.sql \
10621_01_mangos_quest_template.sql \
README
100 changes: 47 additions & 53 deletions src/game/ObjectMgr.cpp
Expand Up @@ -3558,47 +3558,47 @@ void ObjectMgr::LoadQuests()

m_ExclusiveQuestGroups.clear();

// 0 1 2 3 4 5 6 7 8
QueryResult *result = WorldDatabase.Query("SELECT entry, Method, ZoneOrSort, SkillOrClass, MinLevel, QuestLevel, Type, RequiredRaces, RequiredSkillValue,"
// 9 10 11 12 13 14 15 16
// 0 1 2 3 4 5 6 7 8 9
QueryResult *result = WorldDatabase.Query("SELECT entry, Method, ZoneOrSort, MinLevel, QuestLevel, Type, RequiredClasses, RequiredRaces, RequiredSkill, RequiredSkillValue,"
// 10 11 12 13 14 15 16 17
"RepObjectiveFaction, RepObjectiveValue, RequiredMinRepFaction, RequiredMinRepValue, RequiredMaxRepFaction, RequiredMaxRepValue, SuggestedPlayers, LimitTime,"
// 17 18 19 20 21 22 23 24 25
// 18 19 20 21 22 23 24 25 26
"QuestFlags, SpecialFlags, CharTitleId, PlayersSlain, BonusTalents, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain,"
// 26 27 28 29
// 27 28 29 30
"RewXPId, SrcItemId, SrcItemCount, SrcSpell,"
// 30 31 32 33 34 35 36 37 38 39 40
// 31 32 33 34 35 36 37 38 39 40 41
"Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, CompletedText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4,"
// 41 42 43 44 45 46 47 48 49 50 51 52
// 42 43 44 45 46 47 48 49 50 51 52 53
"ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemId5, ReqItemId6, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4, ReqItemCount5, ReqItemCount6,"
// 53 54 55 56 57 58 59 60
// 54 55 56 57 58 59 60 61
"ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4,"
// 61 62 63 64 65 66 67 68
// 62 63 64 65 66 67 68 69
"ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4,"
// 69 70 71 72
// 70 71 72 73
"ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4,"
// 73 74 75 76 77 78
// 74 75 76 77 78 79
"RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6,"
// 79 80 81 82 83 84
// 80 81 82 83 84 85
"RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6,"
// 85 86 87 88 89 90 91 92
// 86 87 88 89 90 91 92 93
"RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4,"
// 93 94 95 96 97
// 94 95 96 97 98
"RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5,"
// 98 99 100 101 102
// 99 100 101 102 103
"RewRepValueId1, RewRepValueId2, RewRepValueId3, RewRepValueId4, RewRepValueId5,"
// 103 104 105 106 107
// 104 105 106 107 108
"RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5,"
// 108 109 110 111 112 113
// 109 110 111 112 113 114
"RewHonorAddition, RewHonorMultiplier, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast,"
// 114 115 116 117 118 119
// 115 116 117 118 119 120
"RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt,"
// 120 121 122 123 124 125 126 127
// 121 122 123 124 125 126 127 128
"DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4,"
// 128 129 130 131 132 133
// 129 130 131 132 133 134
"IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
// 134 135 136 137
// 135 136 137 138
"OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4,"
// 138 139
// 139 140
"StartScript, CompleteScript"
" FROM quest_template");
if (result == NULL)
Expand Down Expand Up @@ -3707,45 +3707,46 @@ void ObjectMgr::LoadQuests()
qinfo->GetQuestId(),qinfo->ZoneOrSort);
// no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check)
}
//check SkillOrClass value (class case).
if (ClassByQuestSort(-int32(qinfo->ZoneOrSort)))
{
// SkillOrClass should not have class case when class case already set in ZoneOrSort.
if (qinfo->SkillOrClass < 0)
{
sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (class sort case) and `SkillOrClass` = %i (class case), redundant.",
qinfo->GetQuestId(),qinfo->ZoneOrSort,qinfo->SkillOrClass);
}
}
//check for proper SkillOrClass value (skill case)

//check for proper RequiredSkill value (skill case)
if (int32 skill_id = SkillByQuestSort(-int32(qinfo->ZoneOrSort)))
{
// skill is positive value in SkillOrClass
if (qinfo->SkillOrClass != skill_id )
if (qinfo->RequiredSkill != skill_id)
{
sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (skill sort case) but `SkillOrClass` does not have a corresponding value (%i).",
sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i but `RequiredSkill` does not have a corresponding value (%i).",
qinfo->GetQuestId(),qinfo->ZoneOrSort,skill_id);
//override, and force proper value here?
}
}
}

// SkillOrClass (class case)
if (qinfo->SkillOrClass < 0)
// RequiredClasses, can be 0/CLASSMASK_ALL_PLAYABLE to allow any class
if (qinfo->RequiredClasses)
{
if (!(qinfo->RequiredClasses & CLASSMASK_ALL_PLAYABLE))
{
sLog.outErrorDb("Quest %u does not contain any playable classes in `RequiredClasses` (%u), value set to 0 (all classes).", qinfo->GetQuestId(), qinfo->RequiredClasses);
qinfo->RequiredClasses = 0;
}
}

// RequiredRaces, can be 0/RACEMASK_ALL_PLAYABLE to allow any race
if (qinfo->RequiredRaces)
{
if (!sChrClassesStore.LookupEntry(-int32(qinfo->SkillOrClass)))
if (!(qinfo->RequiredRaces & RACEMASK_ALL_PLAYABLE))
{
sLog.outErrorDb("Quest %u has `SkillOrClass` = %i (class case) but class (%i) does not exist",
qinfo->GetQuestId(),qinfo->SkillOrClass,-qinfo->SkillOrClass);
sLog.outErrorDb("Quest %u does not contain any playable races in `RequiredRaces` (%u), value set to 0 (all races).", qinfo->GetQuestId(), qinfo->RequiredRaces);
qinfo->RequiredRaces = 0;
}
}
// SkillOrClass (skill case)
if (qinfo->SkillOrClass > 0)

// RequiredSkill, can be 0
if (qinfo->RequiredSkill)
{
if (!sSkillLineStore.LookupEntry(qinfo->SkillOrClass))
if (!sSkillLineStore.LookupEntry(qinfo->RequiredSkill))
{
sLog.outErrorDb("Quest %u has `SkillOrClass` = %u (skill case) but skill (%i) does not exist",
qinfo->GetQuestId(),qinfo->SkillOrClass,qinfo->SkillOrClass);
sLog.outErrorDb("Quest %u has `RequiredSkill` = %u but this skill does not exist",
qinfo->GetQuestId(), qinfo->RequiredSkill);
}
}

Expand All @@ -3757,13 +3758,6 @@ void ObjectMgr::LoadQuests()
qinfo->GetQuestId(),qinfo->RequiredSkillValue,sWorld.GetConfigMaxSkillValue());
// no changes, quest can't be done for this requirement
}

if (qinfo->SkillOrClass <= 0)
{
sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but `SkillOrClass` = %i (class case), value ignored.",
qinfo->GetQuestId(),qinfo->RequiredSkillValue,qinfo->SkillOrClass);
// no changes, quest can't be done for this requirement (fail at wrong skill id)
}
}
// else Skill quests can have 0 skill level, this is ok

Expand Down
66 changes: 29 additions & 37 deletions src/game/Player.cpp
Expand Up @@ -13274,7 +13274,7 @@ Quest const* Player::GetNextQuest(uint64 guid, Quest const *pQuest)

bool Player::CanSeeStartQuest( Quest const *pQuest ) const
{
if (SatisfyQuestRace( pQuest, false ) && SatisfyQuestSkillOrClass( pQuest, false ) &&
if (SatisfyQuestClass(pQuest, false) && SatisfyQuestRace(pQuest, false) && SatisfyQuestSkill(pQuest, false) &&
SatisfyQuestExclusiveGroup( pQuest, false ) && SatisfyQuestReputation( pQuest, false ) &&
SatisfyQuestPreviousQuest( pQuest, false ) && SatisfyQuestNextChain( pQuest, false ) &&
SatisfyQuestPrevChain( pQuest, false ) && SatisfyQuestDay( pQuest, false ) && SatisfyQuestWeek( pQuest, false ))
Expand All @@ -13288,8 +13288,8 @@ bool Player::CanSeeStartQuest( Quest const *pQuest ) const
bool Player::CanTakeQuest( Quest const *pQuest, bool msg ) const
{
return SatisfyQuestStatus( pQuest, msg ) && SatisfyQuestExclusiveGroup( pQuest, msg )
&& SatisfyQuestRace( pQuest, msg ) && SatisfyQuestLevel( pQuest, msg )
&& SatisfyQuestSkillOrClass( pQuest, msg ) && SatisfyQuestReputation( pQuest, msg )
&& SatisfyQuestClass(pQuest, msg) && SatisfyQuestRace(pQuest, msg) && SatisfyQuestLevel(pQuest, msg)
&& SatisfyQuestSkill(pQuest, msg) && SatisfyQuestReputation(pQuest, msg)
&& SatisfyQuestPreviousQuest( pQuest, msg ) && SatisfyQuestTimed( pQuest, msg )
&& SatisfyQuestNextChain( pQuest, msg ) && SatisfyQuestPrevChain( pQuest, msg )
&& SatisfyQuestDay( pQuest, msg ) && SatisfyQuestWeek( pQuest, msg );
Expand Down Expand Up @@ -13766,47 +13766,21 @@ void Player::FailQuest(uint32 questId)
}
}

bool Player::SatisfyQuestSkillOrClass( Quest const* qInfo, bool msg ) const
bool Player::SatisfyQuestSkill(Quest const* qInfo, bool msg) const
{
int32 zoneOrSort = qInfo->GetZoneOrSort();
int32 skillOrClass = qInfo->GetSkillOrClass();
uint32 skill = qInfo->GetRequiredSkill();

// skip zone zoneOrSort and 0 case skillOrClass
if (zoneOrSort >= 0 && skillOrClass == 0)
// skip 0 case RequiredSkill
if (skill == 0)
return true;

int32 questSort = -zoneOrSort;
uint8 reqSortClass = ClassByQuestSort(questSort);

// check class sort cases in zoneOrSort
if (reqSortClass != 0 && getClass() != reqSortClass)
// check skill value
if (GetSkillValue(skill) < qInfo->GetRequiredSkillValue())
{
if (msg)
SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
return false;
}
SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);

// check class
if( skillOrClass < 0 )
{
uint8 reqClass = -int32(skillOrClass);
if(getClass() != reqClass)
{
if( msg )
SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
return false;
}
}
// check skill
else if( skillOrClass > 0 )
{
uint32 reqSkill = skillOrClass;
if( GetSkillValue( reqSkill ) < qInfo->GetRequiredSkillValue() )
{
if( msg )
SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
return false;
}
return false;
}

return true;
Expand Down Expand Up @@ -13928,6 +13902,24 @@ bool Player::SatisfyQuestPreviousQuest( Quest const* qInfo, bool msg ) const
return false;
}

bool Player::SatisfyQuestClass(Quest const* qInfo, bool msg) const
{
uint32 reqClass = qInfo->GetRequiredClasses();

if (reqClass == 0)
return true;

if ((reqClass & getClassMask()) == 0)
{
if (msg)
SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);

return false;
}

return true;
}

bool Player::SatisfyQuestRace( Quest const* qInfo, bool msg ) const
{
uint32 reqraces = qInfo->GetRequiredRaces();
Expand Down
3 changes: 2 additions & 1 deletion src/game/Player.h
Expand Up @@ -1421,10 +1421,11 @@ class MANGOS_DLL_SPEC Player : public Unit
void RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce = true );

void FailQuest( uint32 quest_id );
bool SatisfyQuestSkillOrClass( Quest const* qInfo, bool msg ) const;
bool SatisfyQuestSkill(Quest const* qInfo, bool msg) const;
bool SatisfyQuestLevel( Quest const* qInfo, bool msg ) const;
bool SatisfyQuestLog( bool msg ) const;
bool SatisfyQuestPreviousQuest( Quest const* qInfo, bool msg ) const;
bool SatisfyQuestClass(Quest const* qInfo, bool msg) const;
bool SatisfyQuestRace( Quest const* qInfo, bool msg ) const;
bool SatisfyQuestReputation( Quest const* qInfo, bool msg ) const;
bool SatisfyQuestStatus( Quest const* qInfo, bool msg ) const;
Expand Down

0 comments on commit a946ebc

Please sign in to comment.