Code:
Index: customclass.sql
===================================================================
--- customclass.sql (revision 0)
+++ customclass.sql (revision 0)
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2010-2011 ArcEntity Productions
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+ ALTER TABLE `characters` ADD COLUMN `customclass` SMALLINT(3) NOT NULL AFTER `class`;
\ No newline at end of file
Index: src/arcemu-world/CharacterHandler.cpp
===================================================================
--- src/arcemu-world/CharacterHandler.cpp (revision 3727)
+++ src/arcemu-world/CharacterHandler.cpp (working copy)
@@ -2,6 +2,7 @@
* ArcEmu MMORPG Server
* Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
* Copyright (C) 2008-2010 <http://www.ArcEmu.org/>
+ * Copyright (C) 2010-2011 ArcEntity Productions
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -971,8 +972,19 @@
if(enter_world && !_player->GetMapMgr())
plr->AddToWorld();
+ if(plr->GetCustomClass()) // Set custom classes power.
+ {
+ switch(plr->GetCustomClass())
+ {
+ case PLAYER_CC_EXAMPLE:
+ {
+ plr->SetPowerType(PLAYER_CC_EXAMPLE_POWERTYPE);
+ plr->SetMaxPower(PLAYER_CC_EXAMPLE_POWERTYPE, 23000);
+ plr->SetPower(PLAYER_CC_EXAMPLE_POWERTYPE, 23000);
+ }break;
+ }
+ }
objmgr.AddPlayer(_player);
-
}
bool ChatHandler::HandleRenameCommand(const char * args, WorldSession * m_session)
Index: src/arcemu-world/Player.cpp
===================================================================
--- src/arcemu-world/Player.cpp (revision 3727)
+++ src/arcemu-world/Player.cpp (working copy)
@@ -2,6 +2,7 @@
* ArcEmu MMORPG Server
* Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
* Copyright (C) 2008-2010 <http://www.ArcEmu.org/>
+ * Copyright (C) 2010-2011 ArcEntity Productions
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -507,7 +508,7 @@
for (i= 0; i<NUM_COOLDOWN_TYPES; i++) {
m_cooldownMap[i].clear();
}
-// m_achievement_points = 0;
+ customclass = PLAYER_CC_NONE;
}
void Player::OnLogin()
@@ -806,7 +807,7 @@
SetStat(STAT_INTELLECT, info->intellect );
SetStat(STAT_SPIRIT, info->spirit );
SetBoundingRadius(0.388999998569489f );
- SetCombatReach(1.5f );
+ SetCombatReach(1.5f);
if( race != RACE_BLOODELF )
{
SetDisplayId(info->displayId + gender );
@@ -818,6 +819,8 @@
SetNativeDisplayId(info->displayId - gender );
}
EventModelChange();
+ if(GetCustomClass())
+ CustomClassDisplay(GetCustomClass()); //Override our display if we have a case for it.
//SetMinDamage(info->mindmg );
//SetMaxDamage(info->maxdmg );
SetAttackPower(info->attackpower );
@@ -2403,6 +2406,7 @@
<< "'" << m_name << "', "
<< uint32(getRace()) << ","
<< uint32(getClass()) << ","
+ << uint32(GetCustomClass()) << "," //Get our custom class from database
<< uint32(getGender()) << ",";
if(GetFaction() != info->factiontemplate)
@@ -2820,7 +2824,7 @@
return;
}
- const uint32 fieldcount = 93;
+ const uint32 fieldcount = 94;
if( result->GetFieldCount() != fieldcount )
{
@@ -2856,6 +2860,7 @@
// Load race/class from fields
setRace(get_next_field.GetUInt8());
setClass(get_next_field.GetUInt8());
+ SetCustomClass(get_next_field.GetUInt8()); //Set our custom class from the database
setGender(get_next_field.GetUInt8());
uint32 cfaction = get_next_field.GetUInt32();
@@ -3440,42 +3445,52 @@
else
soberFactor = 1 - timediff / 900;
SetDrunkValue( uint16( soberFactor * get_next_field.GetUInt32() ) );
-
- for (uint8 s = 0; s < MAX_SPEC_COUNT; ++s)
+ //Make sure we are allowed to have our talents and glyphs
+ if(!(GetCustomClass() && CustomClassOverridesCurrent(GetCustomClass())))
{
- start = (char*)get_next_field.GetString();
- uint8 glyphid = 0;
- while(glyphid < GLYPHS_COUNT)
+ for (uint8 s = 0; s < MAX_SPEC_COUNT; ++s)
{
- end = strchr(start,',');
- if(!end)break;
- *end= 0;
- m_specs[s].glyphs[glyphid] = (uint16)atol(start);
- ++glyphid;
- start = end + 1;
- }
+ start = (char*)get_next_field.GetString();
+ uint8 glyphid = 0;
+ while(glyphid < GLYPHS_COUNT)
+ {
+ end = strchr(start,',');
+ if(!end)break;
+ *end= 0;
+ m_specs[s].glyphs[glyphid] = (uint16)atol(start);
+ ++glyphid;
+ start = end + 1;
+ }
- //Load talents for spec
- start = (char*)get_next_field.GetString();
- while(end != NULL)
- {
- end = strchr(start,',');
- if(!end)
- break;
- *end= 0;
- uint32 talentid = atol(start);
- start = end + 1;
+ //Load talents for spec
+ start = (char*)get_next_field.GetString();
+ while(end != NULL)
+ {
+ end = strchr(start,',');
+ if(!end)
+ break;
+ *end= 0;
+ uint32 talentid = atol(start);
+ start = end + 1;
- end = strchr(start,',');
- if(!end)
- break;
- *end= 0;
- uint8 rank = (uint8)atol(start);
- start = end + 1;
+ end = strchr(start,',');
+ if(!end)
+ break;
+ *end= 0;
+ uint8 rank = (uint8)atol(start);
+ start = end + 1;
- m_specs[s].talents.insert(pair<uint32, uint8>(talentid, rank));
+ m_specs[s].talents.insert(make_pair<uint32, uint8>(talentid, rank));
+ }
}
}
+ else
+ {
+ field_index++;
+ field_index++;
+ field_index++;
+ field_index++;
+ }
m_talentSpecsCount = get_next_field.GetUInt8();
m_talentActiveSpec = get_next_field.GetUInt8();
@@ -3496,32 +3511,48 @@
BaseStats[x]=GetStat(x);
UpdateGlyphs();
-
- for (uint8 i = 0; i < GLYPHS_COUNT; ++i)
+ //Make sure we are allowed to have our talents and glyphs
+ if(!(GetCustomClass() && CustomClassOverridesCurrent(GetCustomClass())))
{
- SetGlyph(i, m_specs[m_talentActiveSpec].glyphs[i]);
+ for (uint8 i = 0; i < GLYPHS_COUNT; ++i)
+ {
+ SetGlyph(i, m_specs[m_talentActiveSpec].glyphs[i]);
+ }
}
-
- //class fixes
- switch(getClass())
+ //Set our custom armor proficiency
+ if(GetCustomClass())
{
- case PALADIN:
- armor_proficiency |= ( 1 << 7 );//LIBRAM
+ switch(GetCustomClass())
+ {
+ case PLAYER_CC_EXAMPLE:
+ {
+ armor_proficiency |= ( 1 << 9 );//TOTEM
+ }break;
+ }
+ }
+ else
+ {
+ //class fixes
+ switch(getClass())
+ {
+ case PALADIN:
+ armor_proficiency |= ( 1 << 7 );//LIBRAM
+ break;
+ case DRUID:
+ armor_proficiency |= ( 1 << 8 );//IDOL
+ break;
+ case SHAMAN:
+ armor_proficiency |= ( 1 << 9 );//TOTEM
+ break;
+ case DEATHKNIGHT:
+ armor_proficiency |= ( 1 << 10 );//SIGIL
+ break;
+ case WARLOCK:
+ case HUNTER:
+ _LoadPet(results[5].result);
+ _LoadPetSpells(results[6].result);
break;
- case DRUID:
- armor_proficiency |= ( 1 << 8 );//IDOL
- break;
- case SHAMAN:
- armor_proficiency |= ( 1 << 9 );//TOTEM
- break;
- case DEATHKNIGHT:
- armor_proficiency |= ( 1 << 10 );//SIGIL
- break;
- case WARLOCK:
- case HUNTER:
- _LoadPet(results[5].result);
- _LoadPetSpells(results[6].result);
- break;
+ }
}
if(m_session->CanUseCommand('c'))
@@ -6619,7 +6650,8 @@
}
}
uint32 l = getLevel();
- if( l > 9 )
+ //Once again make sure we can have our talents
+ if( l > 9 && !(GetCustomClass() && CustomClassOverridesCurrent(GetCustomClass())) )
{
SetTalentPoints(SPEC_PRIMARY, l - 9);
}
@@ -13510,4 +13542,72 @@
WorldPacket *data = sChatHandler.FillMessageData(type, lang, msg, GetGUID());
SendMessageToSet( data, true );
+}
+//This is where the magic happens!
+bool Player::SetCustomClass(uint8 cclass, bool overridecurrent /* = false */)
+{
+ if(GetCustomClass() == cclass)
+ return false;
+
+ if(overridecurrent)
+ {
+ Reset_Spells();
+ Reset_Talents();
+ }
+ switch(cclass)
+ {
+ case PLAYER_CC_EXAMPLE:
+ {
+ _RemoveAllSkills();
+ _AddLanguages(true);
+ LearnCustomClassSpells(PLAYER_CC_EXAMPLE);
+ armor_proficiency |= ( 1 << 9 );
+ }break;
+ }
+
+ customclass = cclass;
+ return true;
+}
+//Learn our spells.
+void Player::LearnCustomClassSpells(uint8 cclass)
+{
+ switch(cclass)
+ {
+ case PLAYER_CC_EXAMPLE:
+ {
+ addSpell(1953);
+ addSpell(64779);
+ addSpell(50978);
+ }break;
+ }
+}
+//Override our display
+void Player::CustomClassDisplay(uint8 cclass)
+{
+ if(!GetCustomClass())
+ return;
+ switch(cclass)
+ {
+ case PLAYER_CC_EXAMPLE:
+ {
+ SetDisplayId(25889);
+ SetNativeDisplayId(25889);
+ EventModelChange();
+ }break;
+ }
+}
+//Check for allowing talenting and spell learning
+bool Player::CustomClassOverridesCurrent(uint8 cclass)
+{
+ if(!GetCustomClass())
+ return false;
+
+ switch(cclass)
+ {
+ case PLAYER_CC_EXAMPLE:
+ {
+ return false;
+ }break;
+ }
+ return false;
}
\ No newline at end of file
Index: src/arcemu-world/Player.h
===================================================================
--- src/arcemu-world/Player.h (revision 3727)
+++ src/arcemu-world/Player.h (working copy)
@@ -2,6 +2,7 @@
* ArcEmu MMORPG Server
* Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
* Copyright (C) 2008-2010 <http://www.ArcEmu.org/>
+ * Copyright (C) 2010-2011 ArcEntity Productions
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -78,6 +79,18 @@
// a character's inventory
//====================================================================
+enum CustomClasses
+{
+ PLAYER_CC_NONE = 0,
+ PLAYER_CC_EXAMPLE = 1,
+};
+
+enum CustomClassesPowerType
+{
+ PLAYER_CC_NONE_POWERTYPE = 0,
+ PLAYER_CC_EXAMPLE_POWERTYPE = 0
+};
+
enum Classes
{
WARRIOR = 1,
@@ -2459,7 +2472,13 @@
uint8 m_talentActiveSpec;
PlayerSpec m_specs[MAX_SPEC_COUNT];
-
+ uint8 GetCustomClass() { return customclass; };
+ bool SetCustomClass(uint8 cclass, bool overridecurrent = false);
+ void LearnCustomClassSpells(uint8 cclass);
+ void CustomClassDisplay(uint8 cclass);
+ bool CustomClassOverridesCurrent(uint8 cclass);
+private:
+ uint8 customclass;
public:
void SendTeleportAckMsg( const LocationVector &v );
void SendUpdateDataToSet( ByteBuffer *groupbuf, ByteBuffer *nongroupbuf, bool sendtoself );
Index: src/arcemu-world/ScriptMgr.cpp
===================================================================
--- src/arcemu-world/ScriptMgr.cpp (revision 3727)
+++ src/arcemu-world/ScriptMgr.cpp (working copy)
@@ -2,6 +2,7 @@
* ArcEmu MMORPG Server
* Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
* Copyright (C) 2008-2010 <http://www.ArcEmu.org/>
+ * Copyright (C) 2010-2011 ArcEntity Productions
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -718,6 +719,9 @@
if( pCreature->isTrainer() || pCreature->isProf() || pCreature->isClass() )
{
+ //Make sure we are allowed to train are class spells.
+ if(pCreature->isClass() && Plr->GetCustomClass() && Plr->CustomClassOverridesCurrent(Plr->GetCustomClass()))
+ return;
Trainer *pTrainer = pCreature->GetTrainer();
if(!pTrainer)
{
Index: src/arcemu-world/WorldSession.cpp
===================================================================
--- src/arcemu-world/WorldSession.cpp (revision 3727)
+++ src/arcemu-world/WorldSession.cpp (working copy)
@@ -2,6 +2,7 @@
* ArcEmu MMORPG Server
* Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
* Copyright (C) 2008-2010 <http://www.ArcEmu.org/>
+ * Copyright (C) 2010-2011 ArcEntity Productions
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -1190,6 +1191,8 @@
void WorldSession::HandleLearnTalentOpcode( WorldPacket & recv_data )
{
CHECK_INWORLD_RETURN
+ if( _player->GetCustomClass() && _player->CustomClassOverridesCurrent(_player->GetCustomClass()))
+ return;
uint32 talent_id, requested_rank, unk;
recv_data >> talent_id >> requested_rank >> unk;
@@ -1242,6 +1245,8 @@
void WorldSession::HandleLearnMultipleTalentsOpcode(WorldPacket &recvPacket){
CHECK_INWORLD_RETURN
+ if( _player->GetCustomClass() && _player->CustomClassOverridesCurrent(_player->GetCustomClass()))
+ return;
uint32 talentcount;
uint32 talentid;
Index: UseExample.cpp
===================================================================
--- UseExample.cpp (revision 0)
+++ UseExample.cpp (revision 0)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010-2011 ArcEntity Productions
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+class SCRIPT_DECL CC_TOTEM : public GossipScript
+{
+public:
+ void GossipHello(Object * pObject, Player * Plr, bool AutoSend)
+ {
+ GossipMenu *Menu;
+ if(Plr->getRace() != RACE_DWARF && Plr->getRace() != RACE_TAUREN)
+ {
+ Plr->CastSpell(Plr, 30127, false);
+ Plr->RemoveItemByGuid(pObject->GetGUID());
+ sChatHandler.SystemMessageToPlr(Plr, "The totem destroys itself, searing your hand as it dissappears");
+ return;
+ }
+
+ objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), 12, Plr);
+
+ if(!Plr->GetCustomClass()) // We have no Custom Class, so send the option.
+ {
+ Menu->AddItem(3, "I wish to become an example custom class.", 0);
+ }
+ else if(Plr->GetCustomClass() == PLAYER_CC_Example) // We are a RuneMaster
+ {
+ Menu->AddItem(9, "Teir 1 talents", 2);
+ Menu->AddItem(9, "Teir 2 talents", 3);
+ Menu->AddItem(9, "Teir 3 talents", 4);
+ Menu->AddItem(9, "Teir 4 talents", 5);
+ Menu->AddItem(9, "Teir 5 talents", 6);
+ }
+
+ Menu->AddItem(0, "Put the Rune Covered Totem away.", 100);
+
+ if(AutoSend)
+ Menu->SendTo(Plr);
+ }
+
+ void GossipSelectOption(Object* pObject, Player* Plr, uint32 Id, uint32 IntId, const char * EnteredCode)
+ {
+ GossipMenu *Menu;
+ switch(IntId)
+ {
+ case 0:
+ {
+ if(!Plr->SetCustomClass(PLAYER_CC_EXAMPLE))
+ sChatHandler.BlueSystemMessageToPlr(Plr, "Class change failed.");
+ Plr->GetItemInterface()->RemoveItemAmtByGuid(pObject->GetGUID(), 1);
+ Plr->GetItemInterface()->AddItemById(ITEMID_MAIN, 1, 0);
+ GossipEnd(pObject, Plr);
+ }break;
+
+ case 1:
+ GossipHello(pObject, Plr, true);
+ break;
+
+ case 2:
+ {
+ objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), 1, Plr);
+ Menu->AddItem(9, "Toughness", 11); // http://www.wowhead.com/spell=49042
+ Menu->AddItem(1, "Return", 1);
+ Menu->SendTo(Plr);
+ }break;
+
+ case 3:
+ {
+ objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), 1, Plr);
+
+ Menu->AddItem(1, "Return", 1);
+ Menu->SendTo(Plr);
+ }break;
+
+ case 4:
+ {
+ objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), 1, Plr);
+
+ Menu->AddItem(1, "Return", 1);
+ Menu->SendTo(Plr);
+ }break;
+
+ case 5:
+ {
+ objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), 1, Plr);
+
+ Menu->AddItem(1, "Return", 1);
+ Menu->SendTo(Plr);
+ }break;
+
+ case 6:
+ {
+ objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), 1, Plr);
+
+ Menu->AddItem(1, "Return", 1);
+ Menu->SendTo(Plr);
+ }break;
+
+ case 11:
+ {
+ objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), 1, Plr);
+ Plr->addSpell(49042);
+ Menu->AddItem(1, "Return", 1);
+ Menu->SendTo(Plr);
+ }break;
+
+ case 100:
+ GossipEnd(pObject, Plr);
+ break;
+
+ default:
+ GossipEnd(pObject, Plr);
+ break;
+ }
+ }
+
+ void GossipEnd(Object * pObject, Player * Plr)
+ {
+ Plr->Gossip_Complete();
+ GossipScript::GossipEnd(pObject, Plr);
+ }
+
+ void Destroy()
+ {
+ delete this;
+ }
+};
+
+void SetupCC_TOTEM(ScriptMgr* mgr)
+{
+ GossipScript * tl = (GossipScript*)new CC_TOTEM;
+ mgr->register_item_gossip_script(1, tl);
+}