realityincarnate
06-07-2009, 02:27 PM
I figured that I should post what I have for the charm scaling, so we aren't doubling our efforts. This diff has most of the evolving code removed since it isn't done yet, but several of the data members and accessors are still in place.
The item scripts are loaded from the quests/items directory, and are named after the CharmFile associated with the item. I created a new exported class for perl, $questitem, which doesn't have many functions right now but that I plan to expand for the evolving/intelligent item stuff.
Here's the diff (sorry, it's kind of big):
Index: common/Item.cpp
================================================== =================
--- common/Item.cpp (revision 637)
+++ common/Item.cpp (working copy)
@@ -367,8 +367,9 @@
void ItemInst::PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id)
{
if (item_id != 0) {
- const ItemInst aug(db, item_id);
- PutAugment(slot,aug);
+ const ItemInst* aug = db->CreateItem(item_id);
+ PutAugment(slot,*aug);
+ safe_delete(aug);
}
}
@@ -1593,3 +1594,210 @@
return true;
}
+
+// Methods for EvoItemInst, the extended ItemInst for evolving/scaling items
+
+// Copy constructors
+EvoItemInst::EvoItemInst(const EvoItemInst ©) {
+ m_use_type=copy.m_use_type;
+ m_item=copy.m_item;
+ m_charges=copy.m_charges;
+ m_price=copy.m_price;
+ m_color=copy.m_color;
+ m_merchantslot=copy.m_merchantslot;
+ m_currentslot=copy.m_currentslot;
+ m_instnodrop=copy.m_instnodrop;
+ m_merchantcount=copy.m_merchantcount;
+ // Copy container contents
+ iter_contents it;
+ for (it=copy.m_contents.begin(); it!=copy.m_contents.end(); it++) {
+ ItemInst* inst_old = it->second;
+ ItemInst* inst_new = NULL;
+
+ if (inst_old) {
+ inst_new = inst_old->Clone();
+ }
+
+ if (inst_new != NULL) {
+ m_contents[it->first] = inst_new;
+ }
+ }
+ m_SerialNumber = copy.m_SerialNumber;
+ m_exp = copy.m_exp;
+ m_evolveLvl = copy.m_evolveLvl;
+ m_activated = copy.m_activated;
+ m_evolveInfo = NULL;
+ if (copy.m_scaledItem)
+ m_scaledItem = new Item_Struct(*copy.m_scaledItem);
+ else
+ m_scaledItem = NULL;
+}
+
+EvoItemInst::EvoItemInst(const ItemInst &basecopy) {
+ EvoItemInst* copy = (EvoItemInst*)&basecopy;
+
+ m_use_type=copy->m_use_type;
+ m_item=copy->m_item;
+ m_charges=copy->m_charges;
+ m_price=copy->m_price;
+ m_color=copy->m_color;
+ m_merchantslot=copy->m_merchantslot;
+ m_currentslot=copy->m_currentslot;
+ m_instnodrop=copy->m_instnodrop;
+ m_merchantcount=copy->m_merchantcount;
+ // Copy container contents
+ iter_contents it;
+ for (it=copy->m_contents.begin(); it!=copy->m_contents.end(); it++) {
+ ItemInst* inst_old = it->second;
+ ItemInst* inst_new = NULL;
+
+ if (inst_old) {
+ inst_new = inst_old->Clone();
+ }
+
+ if (inst_new != NULL) {
+ m_contents[it->first] = inst_new;
+ }
+ }
+ m_SerialNumber = copy->m_SerialNumber;
+ m_exp = 0;
+ m_evolveLvl = 0;
+ m_activated = false;
+ m_evolveInfo = NULL;
+ m_scaledItem = NULL;
+}
+
+EvoItemInst::EvoItemInst(const Item_Struct* item, sint16 charges) {
+ m_use_type = ItemUseNormal;
+ m_item = item;
+ m_charges = charges;
+ m_price = 0;
+ m_instnodrop = false;
+ m_merchantslot = 0;
+ if(m_item &&m_item->ItemClass == ItemClassCommon)
+ m_color = m_item->Color;
+ else
+ m_color = 0;
+ m_merchantcount = 1;
+ m_SerialNumber = GetNextItemInstSerialNumber();
+ m_exp = 0;
+ m_evolveLvl = 0;
+ m_activated = false;
+ m_evolveInfo = NULL;
+ m_scaledItem = NULL;
+}
+
+EvoItemInst::~EvoItemInst() {
+ safe_delete(m_scaledItem);
+}
+
+EvoItemInst* EvoItemInst::Clone() const {
+ return new EvoItemInst(*this);
+}
+
+const Item_Struct* EvoItemInst::GetItem() const {
+ if(!m_scaledItem)
+ return m_item;
+ else
+ return m_scaledItem;
+}
+
+const Item_Struct* EvoItemInst::GetUnscaledItem() const {
+ return m_item;
+}
+
+void EvoItemInst::Initialize(SharedDatabase *db) {
+ // if there's no actual item, don't do anything
+ if(!m_item) return;
+
+ // initialize scaling items
+ if (m_item->CharmFileID != 0) {
+ m_evolveLvl = -1;
+ this->ScaleItem();
+ }
+
+ // initialize evolving items
+ else if ((db) && m_item->LoreGroup >= 1000 && m_item->LoreGroup != -1) {
+ // not complete yet
+ }
+}
+
+void EvoItemInst::ScaleItem() {
+ // free memory from any previously scaled item data
+ safe_delete(m_scaledItem);
+
+ m_scaledItem = new Item_Struct(*m_item);
+ float Mult = (float)(GetExp())/10000; // scaling is determined by exp, with 10,000 being full stats
+
+ m_scaledItem->AAgi = m_item->AAgi*Mult;
+ m_scaledItem->AC = m_item->AC*Mult;
+ m_scaledItem->ACha = m_item->ACha*Mult;
+ m_scaledItem->ADex = m_item->ADex*Mult;
+ m_scaledItem->AInt = m_item->AInt*Mult;
+ m_scaledItem->ASta = m_item->AStr*Mult;
+ m_scaledItem->AWis = m_item->AWis*Mult;
+ m_scaledItem->CR = m_item->CR*Mult;
+ m_scaledItem->Damage = m_item->Damage*Mult;
+ m_scaledItem->DamageShield = m_item->DamageShield*Mult;
+ m_scaledItem->DotShielding = m_item->DotShielding*Mult;
+ m_scaledItem->DR = m_item->DR*Mult;
+ m_scaledItem->Endur = m_item->Endur*Mult;
+ m_scaledItem->EnduranceRegen = m_item->EnduranceRegen*Mult;
+ m_scaledItem->FR = m_item->FR*Mult;
+ m_scaledItem->Haste = m_item->Haste*Mult;
+ m_scaledItem->HP = m_item->HP*Mult;
+ m_scaledItem->Mana = m_item->Mana*Mult;
+ m_scaledItem->ManaRegen = m_item->ManaRegen*Mult;
+ m_scaledItem->MR = m_item->MR*Mult;
+ m_scaledItem->PR = m_item->PR*Mult;
+ m_scaledItem->Regen = m_item->Regen*Mult;
+ m_scaledItem->Shielding = m_item->Shielding*Mult;
+ m_scaledItem->SpellShield = m_item->SpellShield*Mult;
+ m_scaledItem->StrikeThrough = m_item->StrikeThrough*Mult;
+ m_scaledItem->StunResist = m_item->StunResist*Mult;
+ m_scaledItem->Avoidance = m_item->Avoidance*Mult;
+ m_scaledItem->CharmFileID = 0; // this stops the client from trying to scale the item itself.
+}
+
+bool EvoItemInst::EvolveOnAllKills() const {
+ return (m_evolveInfo && m_evolveInfo->AllKills);
+}
+
+sint8 EvoItemInst::GetMaxEvolveLvl() const {
+ if(m_evolveInfo)
+ return m_evolveInfo->MaxLvl;
+ else
+ return 0;
+}
+
+uint32 EvoItemInst::GetKillsNeeded(uint8 currentlevel) {
+ uint32 kills = -1; // default to -1 (max uint32 value) because this value is usually divided by, so we don't want to ever return zero.
+ if (m_evolveInfo)
+ if (currentlevel != m_evolveInfo->MaxLvl)
+ kills = m_evolveInfo->LvlKills[currentlevel-1];
+
+ if (kills == 0)
+ kills = -1;
+
+ return kills;
+}
+
+EvolveInfo::EvolveInfo() {
+ // nothing here yet
+}
+
+EvolveInfo::EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10) {
+ FirstItem = first;
+ MaxLvl = max;
+ AllKills = allkills;
+ LvlKills[0] = L2;
+ LvlKills[1] = L3;
+ LvlKills[2] = L4;
+ LvlKills[3] = L5;
+ LvlKills[4] = L6;
+ LvlKills[5] = L7;
+ LvlKills[6] = L8;
+ LvlKills[7] = L9;
+ LvlKills[8] = L10;
+}
+
Index: common/Item.h
================================================== =================
--- common/Item.h (revision 637)
+++ common/Item.h (working copy)
@@ -27,6 +27,8 @@
class ItemInstQueue; // Queue of ItemInst objects (i.e., cursor)
class Inventory; // Character inventory
class ItemParse; // Parses item packets
+class EvoItemInst; // Extended item inst, for use with scaling/evolving items
+class EvolveInfo; // Stores information about an evolving item family
#include <string>
#include <vector>
@@ -306,7 +308,7 @@
// Accessors
const uint32 GetID() const { return m_item->ID; }
- const Item_Struct* GetItem() const { return m_item; }
+ virtual const Item_Struct* GetItem() const { return m_item; }
void SetItem(const Item_Struct* item) { m_item = item; }
sint16 GetCharges() const { return m_charges; }
@@ -349,6 +351,9 @@
inline sint32 GetSerialNumber() const { return m_SerialNumber; }
inline void SetSerialNumber(sint32 id) { m_SerialNumber = id; }
+ virtual bool IsScaling() const { return false; }
+ virtual bool IsEvolving() const { return false; }
+
protected:
//////////////////////////
// Protected Members
@@ -377,4 +382,55 @@
};
+class EvoItemInst: public ItemInst {
+public:
+ // constructor and destructor
+ EvoItemInst(const EvoItemInst& copy);
+ EvoItemInst(const ItemInst& copy);
+ EvoItemInst(const Item_Struct* item = NULL, sint16 charges = 0);
+ ~EvoItemInst();
+
+ // accessors... a lot of these are for evolving items (not complete yet)
+ bool IsScaling() const { return (m_evolveLvl == -1); }
+ bool IsEvolving() const { return (m_evolveLvl >= 1); }
+ uint32 GetExp() const { return m_exp; }
+ void SetExp(uint32 exp) { m_exp = exp; }
+ void AddExp(uint32 exp) { m_exp += exp; }
+ bool IsActivated() { return m_activated; }
+ void SetActivated(bool activated) { m_activated = activated; }
+ sint8 GetEvolveLvl() const { return m_evolveLvl; }
+
+ EvoItemInst* Clone() const;
+ const Item_Struct* GetItem() const;
+ const Item_Struct* GetUnscaledItem() const;
+ void Initialize(SharedDatabase *db = NULL);
+ void ScaleItem();
+ bool EvolveOnAllKills() const;
+ sint8 GetMaxEvolveLvl() const;
+ uint32 GetKillsNeeded(uint8 currentlevel);
+
+
+private:
+ uint32 m_exp;
+ sint8 m_evolveLvl;
+ bool m_activated;
+ Item_Struct* m_scaledItem;
+ const EvolveInfo* m_evolveInfo;
+};
+
+class EvolveInfo {
+public:
+ friend class EvoItemInst;
+ //temporary
+ uint16 LvlKills[9];
+ uint32 FirstItem;
+ uint8 MaxLvl;
+ bool AllKills;
+
+ EvolveInfo();
+ EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10);
+ ~EvolveInfo();
+};
+
+
#endif // #define __ITEM_H
Index: common/shareddb.cpp
================================================== =================
--- common/shareddb.cpp (revision 637)
+++ common/shareddb.cpp (working copy)
@@ -394,10 +394,13 @@
myitem = GetItem(itemid);
if(!myitem)
continue;
- ItemInst myinst(myitem, charges);
+
+ ItemInst* myinst = CreateBaseItem(myitem, charges);
+
if(slot < 0)
slot = inv->FindFreeSlot(0,0);
- inv->PutItem(slot, myinst);
+ inv->PutItem(slot, *myinst);
+ safe_delete(myinst);
}
if(result) mysql_free_result(result);
@@ -442,16 +445,19 @@
if (item) {
sint16 put_slot_id = SLOT_INVALID;
- ItemInst inst(item, charges);
+ ItemInst* inst = CreateBaseItem(item, charges);
+
if (item->ItemClass == ItemClassCommon) {
for(int i=0;i<5;i++) {
if (aug[i]) {
- inst.PutAugment(this, i, aug[i]);
+ inst->PutAugment(this, i, aug[i]);
}
}
}
- put_slot_id = inv->PutItem(slot_id, inst);
+ put_slot_id = inv->PutItem(slot_id, *inst);
+ safe_delete(inst);
+
// Save ptr to item in inventory
if (put_slot_id == SLOT_INVALID) {
LogFile->write(EQEMuLog::Error,
@@ -511,28 +517,30 @@
if (item) {
sint16 put_slot_id = SLOT_INVALID;
- ItemInst inst(item, charges);
- if (instnodrop || (slot_id >= 0 && slot_id <= 21 && inst.GetItem()->Attuneable))
- inst.SetInstNoDrop(true);
+ ItemInst* inst = CreateBaseItem(item, charges);
+
+ if (instnodrop || (slot_id >= 0 && slot_id <= 21 && inst->GetItem()->Attuneable))
+ inst->SetInstNoDrop(true);
if (color > 0)
- inst.SetColor(color);
+ inst->SetColor(color);
if(charges==255)
- inst.SetCharges(-1);
+ inst->SetCharges(-1);
else
- inst.SetCharges(charges);
+ inst->SetCharges(charges);
if (item->ItemClass == ItemClassCommon) {
for(int i=0;i<5;i++) {
if (aug[i]) {
- inst.PutAugment(this, i, aug[i]);
+ inst->PutAugment(this, i, aug[i]);
}
}
}
if (slot_id>=8000 && slot_id <= 8999)
- put_slot_id = inv->PushCursor(inst);
+ put_slot_id = inv->PushCursor(*inst);
else
- put_slot_id = inv->PutItem(slot_id, inst);
+ put_slot_id = inv->PutItem(slot_id, *inst);
+ safe_delete(inst);
// Save ptr to item in inventory
if (put_slot_id == SLOT_INVALID) {
@@ -590,23 +598,26 @@
if(!item)
continue;
- ItemInst inst(item, charges);
- inst.SetInstNoDrop(instnodrop);
+ ItemInst* inst = CreateBaseItem(item, charges);
+
+ inst->SetInstNoDrop(instnodrop);
if (color > 0)
- inst.SetColor(color);
- inst.SetCharges(charges);
+ inst->SetColor(color);
+ inst->SetCharges(charges);
if (item->ItemClass == ItemClassCommon) {
for(int i=0;i<5;i++) {
if (aug[i]) {
- inst.PutAugment(this, i, aug[i]);
+ inst->PutAugment(this, i, aug[i]);
}
}
}
+
if (slot_id>=8000 && slot_id <= 8999)
- put_slot_id = inv->PushCursor(inst);
+ put_slot_id = inv->PushCursor(*inst);
else
- put_slot_id = inv->PutItem(slot_id, inst);
+ put_slot_id = inv->PutItem(slot_id, *inst);
+ safe_delete(inst);
// Save ptr to item in inventory
if (put_slot_id == SLOT_INVALID) {
@@ -1241,7 +1252,7 @@
ItemInst* inst = NULL;
item = GetItem(item_id);
if (item) {
- inst = new ItemInst(item, charges);
+ inst = CreateBaseItem(item, charges);
inst->PutAugment(this, 0, aug1);
inst->PutAugment(this, 1, aug2);
inst->PutAugment(this, 2, aug3);
@@ -1261,18 +1272,34 @@
if (item) {
if (charges == 0)
charges = item->MaxCharges;
- inst = new ItemInst(item, charges);
+ inst = CreateBaseItem(item, charges);
inst->PutAugment(this, 0, aug1);
inst->PutAugment(this, 1, aug2);
inst->PutAugment(this, 2, aug3);
inst->PutAugment(this, 3, aug4);
inst->PutAugment(this, 4, aug5);
- inst->SetCharges(charges);
+ //inst->SetCharges(charges);
}
return inst;
}
+ItemInst* SharedDatabase::CreateBaseItem(const Item_Struct* item, sint16 charges) {
+ ItemInst* inst = NULL;
+ if (item) {
+ if (charges == 0)
+ charges = item->MaxCharges;
+
+ if(item->CharmFileID != 0 || (item->LoreGroup >= 1000 && item->LoreGroup != -1)) {
+ inst = new EvoItemInst(item, charges);
+ ((EvoItemInst*)inst)->Initialize(this);
+ }
+ else
+ inst = new ItemInst(item, charges);
+ }
+ return inst;
+}
+
sint32 SharedDatabase::DeleteStalePlayerCorpses() {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
@@ -1489,3 +1516,6 @@
}
}
+const EvolveInfo* SharedDatabase::GetEvolveInfo(uint32 loregroup) {
+ return NULL; // nothing here for now... database and/or sharemem pulls later
+}
\ No newline at end of file
Index: common/shareddb.h
================================================== =================
--- common/shareddb.h (revision 637)
+++ common/shareddb.h (working copy)
@@ -6,6 +6,7 @@
#include "database.h"
#include "skills.h"
#include "../zone/spdat.h"
+#include "item.h"
#include <list>
@@ -62,6 +63,7 @@
*/
ItemInst* CreateItem(uint32 item_id, sint16 charges=0, uint32 aug1=0, uint32 aug2=0, uint32 aug3=0, uint32 aug4=0, uint32 aug5=0);
ItemInst* CreateItem(const Item_Struct* item, sint16 charges=0, uint32 aug1=0, uint32 aug2=0, uint32 aug3=0, uint32 aug4=0, uint32 aug5=0);
+ ItemInst* CreateBaseItem(const Item_Struct* item, sint16 charges=0);
/*
@@ -72,7 +74,8 @@
inline const int32 GetMaxLootDropID() { return lootdrop_max; }
inline const int32 GetMaxNPCType() { return max_npc_type; }
inline const int32 GetMaxNPCFactionList() { return npcfactionlist_max; }
- const Item_Struct* GetItem(uint32 id);
+ const Item_Struct* GetItem(uint32 id);
+ const EvolveInfo* GetEvolveInfo(uint32 loregroup);
const NPCFactionList* GetNPCFactionEntry(uint32 id);
int16 GetSkillCap(int8 Class_, SkillType Skill, int8 Level);
int8 GetTrainLevel(int8 Class_, SkillType Skill, int8 Level);
Index: zone/bonuses.cpp
================================================== =================
--- zone/bonuses.cpp (revision 637)
+++ zone/bonuses.cpp (working copy)
@@ -26,6 +26,7 @@
#include "../common/bodytypes.h"
#include "../common/classes.h"
#include "../common/rulesys.h"
+#include "embparser.h"
#include <math.h>
#include <assert.h>
#ifndef WIN32
@@ -147,6 +148,9 @@
const ItemInst* inst = m_inv[i];
if(inst == 0)
continue;
+ if(inst->IsScaling()) {
+ CalcScale(const_cast<ItemInst*>(inst), i);
+ }
AddItemBonuses(inst, newbon);
}
@@ -1176,3 +1180,17 @@
}
}
+
+void Client::CalcScale(ItemInst* iteminst, sint16 slot_id) {
+ EvoItemInst* inst = (EvoItemInst*)iteminst;
+ uint16 oldexp = inst->GetExp();
+
+ #ifdef EMBPERL
+ ((PerlembParser *)parse)->Event(EVENT_SCALE_CALC, inst->GetID(), "", inst, this);
+ #endif
+
+ if (inst->GetExp() != oldexp) { // if the scaling factor changed, rescale the item and update the client
+ inst->ScaleItem();
+ this->SendItemPacket(slot_id, inst, ItemPacketTrade);
+ }
+}
Index: zone/client.h
================================================== =================
--- zone/client.h (revision 637)
+++ zone/client.h (working copy)
@@ -44,6 +44,7 @@
#include "questmgr.h"
#include <float.h>
#include <set>
+#include "../common/item_struct.h"
#define CLIENT_TIMEOUT 90000
#define CLIENT_LD_TIMEOUT 30000 // length of time client stays in zone after LDing
@@ -439,6 +440,7 @@
FACTION_VALUE GetReverseFactionCon(Mob* iOther);
FACTION_VALUE GetFactionLevel(int32 char_id, int32 npc_id, int32 p_race, int32 p_class, int32 p_deity, sint32 pFaction, Mob* tnpc);
sint32 GetCharacterFactionLevel(sint32 faction_id);
+ sint32 GetModCharacterFactionLevel(sint32 faction_id);
void SetFactionLevel(int32 char_id, int32 npc_id, int8 char_class, int8 char_race, int8 char_deity);
void SetFactionLevel2(int32 char_id, sint32 faction_id, int8 char_class, int8 char_race, int8 char_deity, sint32 value);
@@ -835,6 +837,8 @@
void HandleLDoNPickLock(NPC *target, int16 skill, int8 type);
int LDoNChest_SkillCheck(NPC *target, int skill);
+ void CalcScale(ItemInst* inst, sint16 slot_id); // determine the multiplication factor for scaled items
+
protected:
friend class Mob;
void CalcItemBonuses(StatBonuses* newbon);
Index: zone/embparser.cpp
================================================== =================
--- zone/embparser.cpp (revision 637)
+++ zone/embparser.cpp (working copy)
@@ -65,7 +65,8 @@
"EVENT_PLAYER_PICKUP",
"EVENT_POPUPRESPONSE",
"EVENT_PROXIMITY_SAY",
- "EVENT_CAST"
+ "EVENT_CAST",
+ "EVENT_SCALE_CALC"
};
PerlembParser::PerlembParser(void) : Parser()
@@ -187,13 +188,13 @@
EventRecord e = eventQueue.front();
eventQueue.pop();
- Event(e.event, e.npcid, e.data.c_str(), e.npcmob, e.mob, e.extradata);
+ EventCommon(e.event, e.objid, e.data.c_str(), e.npcmob, e.iteminst, e.mob, e.extradata);
}
eventQueueProcessing = false;
}
-void PerlembParser::Event(QuestEventID event, int32 npcid, const char * data, NPC* npcmob, Mob* mob, int32 extradata)
+void PerlembParser::EventCommon(QuestEventID event, int32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, int32 extradata)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
@@ -210,10 +211,11 @@
//queue the event for later.
EventRecord e;
e.event = event;
- e.npcid = npcid;
+ e.objid = objid;
if(data != NULL)
e.data = data;
e.npcmob = npcmob;
+ e.iteminst = iteminst;
e.mob = mob;
e.extradata = extradata;
eventQueue.push(e);
@@ -221,19 +223,41 @@
}
bool isPlayerQuest = false;
- if(!npcmob && mob)
- isPlayerQuest = true;
-
+ bool isItemQuest = false;
+ if(!npcmob && mob) {
+ if(!iteminst)
+ isPlayerQuest = true;
+ else
+ isItemQuest = true;
+ }
+
string packagename;
- if(!isPlayerQuest){
- packagename = GetPkgPrefix(npcid);
+ if(!isPlayerQuest && !isItemQuest){
+ packagename = GetPkgPrefix(objid);
if(!isloaded(packagename.c_str()))
{
- LoadScript(npcid, zone->GetShortName());
+ LoadScript(objid, zone->GetShortName());
}
}
+ else if(isItemQuest) {
+ const Item_Struct* item = iteminst->GetItem();
+ if (!item) return;
+
+ if (event == EVENT_SCALE_CALC) {
+ packagename = item->CharmFile;
+ if(!isloaded(packagename.c_str())) {
+ LoadItemScript(iteminst, packagename, itemQuestScale);
+ }
+ }
+ else {
+ packagename = "item_";
+ packagename += itoa(objid);
+ if(!isloaded(packagename.c_str()))
+ LoadItemScript(iteminst, packagename, itemQuestID);
+ }
+ }
else {
packagename = "player";
packagename += "_";
@@ -262,7 +286,7 @@
ExportVar(packagename.c_str(), "charid", charid);
- if(!isPlayerQuest){
+ if(!isPlayerQuest && !isItemQuest){
//only export globals if the npcmob has the qglobal flag
if(npcmob && npcmob->GetQglobal()){
// Delete expired global variables
@@ -337,7 +361,7 @@
// ExportVar(packagename.c_str(), "cumflag", mob->CastToClient()->flag[50]);
}
- if(!isPlayerQuest){
+ if(!isPlayerQuest && !isItemQuest){
if (mob && npcmob && mob->IsClient() && npcmob->IsNPC()) {
Client* client = mob->CastToClient();
NPC* npc = npcmob->CastToNPC();
@@ -362,7 +386,7 @@
ExportVar(packagename.c_str(), "userid", mob->GetID());
}
- if(!isPlayerQuest){
+ if(!isPlayerQuest && !isItemQuest){
if (npcmob)
{
ExportVar(packagename.c_str(), "mname", npcmob->GetName());
@@ -440,7 +464,7 @@
switch (event) {
case EVENT_SAY: {
npcmob->FaceTarget(mob);
- ExportVar(packagename.c_str(), "data", npcid);
+ ExportVar(packagename.c_str(), "data", objid);
ExportVar(packagename.c_str(), "text", data);
ExportVar(packagename.c_str(), "langid", extradata);
break;
@@ -448,14 +472,14 @@
case EVENT_ITEM: {
npcmob->FaceTarget(mob);
//this is such a hack... why arnt these just set directly..
- ExportVar(packagename.c_str(), "item1", GetVar("item1", npcid).c_str());
- ExportVar(packagename.c_str(), "item2", GetVar("item2", npcid).c_str());
- ExportVar(packagename.c_str(), "item3", GetVar("item3", npcid).c_str());
- ExportVar(packagename.c_str(), "item4", GetVar("item4", npcid).c_str());
- ExportVar(packagename.c_str(), "copper", GetVar("copper", npcid).c_str());
- ExportVar(packagename.c_str(), "silver", GetVar("silver", npcid).c_str());
- ExportVar(packagename.c_str(), "gold", GetVar("gold", npcid).c_str());
- ExportVar(packagename.c_str(), "platinum", GetVar("platinum", npcid).c_str());
+ ExportVar(packagename.c_str(), "item1", GetVar("item1", objid).c_str());
+ ExportVar(packagename.c_str(), "item2", GetVar("item2", objid).c_str());
+ ExportVar(packagename.c_str(), "item3", GetVar("item3", objid).c_str());
+ ExportVar(packagename.c_str(), "item4", GetVar("item4", objid).c_str());
+ ExportVar(packagename.c_str(), "copper", GetVar("copper", objid).c_str());
+ ExportVar(packagename.c_str(), "silver", GetVar("silver", objid).c_str());
+ ExportVar(packagename.c_str(), "gold", GetVar("gold", objid).c_str());
+ ExportVar(packagename.c_str(), "platinum", GetVar("platinum", objid).c_str());
string hashname = packagename + std::string("::itemcount");
perl->eval(std::string("%").append(hashname).append(" = ();").c_str());
perl->eval(std::string("++$").append(hashname).append("{$").append(packagename).append("::item1};").c_str());
@@ -531,7 +555,7 @@
}
case EVENT_AGGRO_SAY: {
- ExportVar(packagename.c_str(), "data", npcid);
+ ExportVar(packagename.c_str(), "data", objid);
ExportVar(packagename.c_str(), "text", data);
ExportVar(packagename.c_str(), "langid", extradata);
break;
@@ -541,11 +565,16 @@
break;
}
case EVENT_PROXIMITY_SAY: {
- ExportVar(packagename.c_str(), "data", npcid);
+ ExportVar(packagename.c_str(), "data", objid);
ExportVar(packagename.c_str(), "text", data);
ExportVar(packagename.c_str(), "langid", extradata);
break;
}
+ case EVENT_SCALE_CALC: {
+ ExportVar(packagename.c_str(), "itemid", objid);
+ ExportVar(packagename.c_str(), "itemname", iteminst->GetItem()->Name);
+ break;
+ }
//nothing special about these events
case EVENT_DEATH:
case EVENT_SPAWN:
@@ -566,16 +595,27 @@
}
if(isPlayerQuest){
- SendCommands(packagename.c_str(), sub_name, 0, mob, mob);
+ this->SendCommands(packagename.c_str(), sub_name, 0, mob, mob, NULL);
}
+ else if(isItemQuest) {
+ this->SendCommands(packagename.c_str(), sub_name, 0, mob, mob, iteminst);
+ }
else {
- SendCommands(packagename.c_str(), sub_name, npcid, npcmob, mob);
+ this->SendCommands(packagename.c_str(), sub_name, objid, npcmob, mob, NULL);
}
//now handle any events that cropped up...
HandleQueue();
}
+void PerlembParser::Event(QuestEventID event, int32 npcid, const char* data, NPC* npcmob, Mob* mob, int32 extradata) {
+ EventCommon(event, npcid, data, npcmob, (ItemInst*)NULL, mob, extradata);
+}
+
+void PerlembParser::Event(QuestEventID event, int32 itemid, const char* data, ItemInst* iteminst, Mob* mob, int32 extradata) {
+ EventCommon(event, itemid, data, (NPC*)NULL, iteminst, mob, extradata);
+}
+
void PerlembParser::ReloadQuests() {
command_clear_perl();
@@ -604,6 +644,7 @@
hasQuests.clear();
playerQuestLoaded.clear();
+ itemQuestLoaded.clear();
}
int PerlembParser::LoadScript(int npcid, const char * zone, Mob* activater)
@@ -846,6 +887,42 @@
return 1;
}
+int PerlembParser::LoadItemScript(ItemInst* iteminst, string packagename, itemQuestMode Qtype) {
+ if(!perl)
+ return 0;
+
+ // if we've already tried to load it, don't try again
+ if(itemQuestLoaded.count(packagename) == 1)
+ return 1;
+
+ string filename = "quests/items/";
+ if(Qtype == itemQuestScale)
+ filename += packagename;
+ else if(Qtype == itemQuestLore) {
+ filename += "lore_";
+ filename += itoa(iteminst->GetItem()->LoreGroup);
+ }
+ else
+ filename += itoa(iteminst->GetID());
+ filename += ".pl";
+ printf("Loading file %s\n",filename.c_str());
+
+ try {
+ perl->eval_file(packagename.c_str(), filename.c_str());
+ }
+ catch(const char* err) {
+ LogFile->write(EQEMuLog::Quest, "WARNING: error compiling quest file %s: %s", filename.c_str(), err);
+ }
+
+ if(!isloaded(packagename.c_str())) {
+ itemQuestLoaded[packagename] = Qtype;
+ return 0;
+ }
+
+ itemQuestLoaded[packagename] = itemQuestUnloaded;
+ return 1;
+}
+
bool PerlembParser::isloaded(const char *packagename) const {
char buffer[120];
snprintf(buffer, 120, "$%s::isloaded", packagename);
@@ -926,7 +1003,7 @@
return(std::string(buf));
}
-void PerlembParser::SendCommands(const char * pkgprefix, const char *event, int32 npcid, Mob* other, Mob* mob)
+void PerlembParser::SendCommands(const char * pkgprefix, const char *event, int32 npcid, Mob* other, Mob* mob, ItemInst* iteminst)
{
if(!perl)
return;
Index: zone/embparser.h
================================================== =================
--- zone/embparser.h (revision 637)
+++ zone/embparser.h (working copy)
@@ -31,11 +31,19 @@
pQuestEventCast // player.pl loaded, has an EVENT_CAST sub
} playerQuestMode;
+typedef enum {
+ itemQuestUnloaded = 1,
+ itemQuestScale,
+ itemQuestLore,
+ itemQuestID
+} itemQuestMode;
+
struct EventRecord {
QuestEventID event;
- int32 npcid;
+ int32 objid;
string data;
NPC* npcmob;
+ ItemInst* iteminst;
Mob* mob;
int32 extradata;
};
@@ -49,12 +57,14 @@
//if they do not have a quest or the default.
map<int32, questMode> hasQuests; //npcid -> questMode
map<std::string, playerQuestMode> playerQuestLoaded; //zone shortname -> playerQuestMode
+ map<std::string, itemQuestMode> itemQuestLoaded; // package name - > itemQuestMode
queue<EventRecord> eventQueue; //for events that happen when perl is in use.
bool eventQueueProcessing;
void HandleQueue();
-
+ void EventCommon(QuestEventID event, int32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, int32 extradata);
+
Embperl * perl;
//export a symbol table of sorts
virtual void map_funs();
@@ -66,8 +76,10 @@
bool isloaded(const char *packagename) const;
// bool isdefault(const char *packagename) const { return perl->geti(std::string("$").append(packagename).append("::isdefault").c_str()); }
void Event(QuestEventID event, int32 npcid, const char * data, NPC* npcmob, Mob* mob, int32 extradata = 0);
+ void Event(QuestEventID event, int32 itemid, const char * data, ItemInst* iteminst, Mob* mob, int32 extradata = 0);
int LoadScript(int npcid, const char * zone, Mob* activater=0);
int LoadPlayerScript(const char *zone);
+ int LoadItemScript(ItemInst* iteminst, string packagename, itemQuestMode Qtype);
//expose a var to the script (probably parallels addvar))
//i.e. exportvar("qst1234", "name", "somemob");
@@ -85,7 +97,7 @@
std::string GetPkgPrefix(int32 npcid, bool defaultOK = true);
//call the appropriate perl handler. afterwards, parse and dispatch the command queue
//SendCommands("qst1234", "EVENT_SAY") would trigger sub EVENT_SAY() from the qst1234.pl file
- virtual void SendCommands(const char * pkgprefix, const char *event, int32 npcid, Mob* other, Mob* mob);
+ virtual void SendCommands(const char * pkgprefix, const char *event, int32 npcid, Mob* other, Mob* mob, ItemInst* iteminst);
virtual void ReloadQuests();
int HasQuestFile(int32 npcid);
Index: zone/embperl.cpp
================================================== =================
--- zone/embperl.cpp (revision 637)
+++ zone/embperl.cpp (working copy)
@@ -37,6 +37,7 @@
EXTERN_C XS(boot_Group);
EXTERN_C XS(boot_Raid);
EXTERN_C XS(boot_PerlPacket);
+EXTERN_C XS(boot_QuestItem);
/*XS(XS_Client_new);
//XS(XS_Mob_new);
XS(XS_NPC_new);
@@ -84,6 +85,7 @@
newXS(strcpy(buf, "PerlPacket::boot_PerlPacket"), boot_PerlPacket, file);
newXS(strcpy(buf, "Group::boot_Group"), boot_Group, file);
newXS(strcpy(buf, "Raid::boot_Raid"), boot_Raid, file);
+ newXS(strcpy(buf, "QuestItem::boot_QuestItem"), boot_QuestItem, file);
#endif
#endif
#ifdef EMBPERL_COMMANDS
Index: zone/event_codes.h
================================================== =================
--- zone/event_codes.h (revision 637)
+++ zone/event_codes.h (working copy)
@@ -31,6 +31,7 @@
EVENT_POPUPRESPONSE,
EVENT_PROXIMITY_SAY,
EVENT_CAST,
+ EVENT_SCALE_CALC,
_LargestEventID
} QuestEventID;
Index: zone/faction.cpp
================================================== =================
--- zone/faction.cpp (revision 637)
+++ zone/faction.cpp (working copy)
@@ -633,6 +633,18 @@
return(res->second);
}
+// returns the character's faction level, adjusted for racial, class, and deity modifiers
+sint32 Client::GetModCharacterFactionLevel(sint32 faction_id) {
+ sint32 Modded = GetCharacterFactionLevel(faction_id);
+ FactionMods fm;
+ if(database.GetFactionData(&fm,GetClass(),GetRace(),GetDeity(),faction_id))
+ Modded += fm.base + fm.class_mod + fm.race_mod + fm.deity_mod;
+ if (Modded > MAX_FACTION)
+ Modded = MAX_FACTION;
+
+ return Modded;
+}
+
bool ZoneDatabase::GetFactionData(FactionMods* fm, uint32 class_mod, uint32 race_mod, uint32 deity_mod, sint32 faction_id) {
if (faction_id <= 0 || faction_id > (sint32) max_faction)
return false;
Index: zone/makefile.common
================================================== =================
--- zone/makefile.common (revision 637)
+++ zone/makefile.common (working copy)
@@ -15,7 +15,7 @@
doors.o command.o beacon.o embxs.o AA.o trap.o client_packet.o \
bonuses.o trading.o spdat.o spell_effects.o aggro.o guild.o \
inventory.o client_mods.o tradeskills.o waypoints.o pets.o zone_profile.o \
- effects.o perl_client.o perl_entity.o perl_mob.o perl_npc.o \
+ effects.o perl_client.o perl_entity.o perl_mob.o perl_questitem.o perl_npc.o \
perl_PlayerCorpse.o perl_groups.o perl_raids.o questmgr.o client_logs.o perlparser.o \
../common/rdtsc.o ../common/extprofile.o horse.o exp.o pathing.o \
fearpath.o special_attacks.o ../common/timeoutmgr.o ../common/Condition.o \
Index: zone/perl_client.cpp
================================================== =================
--- zone/perl_client.cpp (revision 637)
+++ zone/perl_client.cpp (working copy)
@@ -3394,6 +3394,33 @@
XSRETURN(1);
}
+XS(XS_Client_GetModCharacterFactionLevel); /* prototype to pass -Wmissing-prototypes */
+XS(XS_Client_GetModCharacterFactionLevel)
+{
+ dXSARGS;
+ if (items != 2)
+ Perl_croak(aTHX_ "Usage: Client::GetModCharacterFactionLevel(THIS, faction_id)");
+ {
+ Client * THIS;
+ sint32 RETVAL;
+ dXSTARG;
+ sint32 faction_id = (sint32)SvIV(ST(1));
+
+ if (sv_derived_from(ST(0), "Client")) {
+ IV tmp = SvIV((SV*)SvRV(ST(0)));
+ THIS = INT2PTR(Client *,tmp);
+ }
+ else
+ Perl_croak(aTHX_ "THIS is not of type Client");
+ if(THIS == NULL)
+ Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
+
+ RETVAL = THIS->GetModCharacterFactionLevel(faction_id);
+ XSprePUSH; PUSHi((IV)RETVAL);
+ }
+ XSRETURN(1);
+}
+
XS(XS_Client_SetZoneFlag); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_SetZoneFlag)
{
@@ -3896,6 +3923,7 @@
newXSproto(strcpy(buf, "ResetTrade"), XS_Client_ResetTrade, file, "$");
newXSproto(strcpy(buf, "UseDiscipline"), XS_Client_UseDiscipline, file, "$$$");
newXSproto(strcpy(buf, "GetCharacterFactionLevel"), XS_Client_GetCharacterFactionLevel, file, "$$");
+ newXSproto(strcpy(buf, "GetModCharacterFactionLevel"), XS_Client_GetModCharacterFactionLevel, file, "$$");
newXSproto(strcpy(buf, "SetZoneFlag"), XS_Client_SetZoneFlag, file, "$$");
newXSproto(strcpy(buf, "ClearZoneFlag"), XS_Client_ClearZoneFlag, file, "$$");
newXSproto(strcpy(buf, "HasZoneFlag"), XS_Client_HasZoneFlag, file, "$$");
Index: zone/perl_groups.cpp
================================================== =================
--- zone/perl_groups.cpp (revision 637)
+++ zone/perl_groups.cpp (working copy)
@@ -575,6 +575,42 @@
XSRETURN(1);
}
+XS(XS_Group_GetMember);
+XS(XS_Group_GetMember)
+{
+ dXSARGS;
+ if (items != 2)
+ Perl_croak(aTHX_ "Usage: Group::GetMember(THIS, index)");
+ {
+ Group * THIS;
+ Mob* member;
+ Client* RETVAL = NULL;
+ dXSTARG;
+
+ if (sv_derived_from(ST(0), "Group")) {
+ IV tmp = SvIV((SV*)SvRV(ST(0)));
+ THIS = INT2PTR(Group *,tmp);
+ }
+ else
+ Perl_croak(aTHX_ "THIS is not of type Group");
+ if(THIS == NULL)
+ Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
+
+ int index = (int)SvUV(ST(1));
+ if (index < 0 || index > 5)
+ RETVAL = NULL;
+ else {
+ member = THIS->members[index];
+ if (member != NULL)
+ RETVAL = member->CastToClient();
+ }
+
+ ST(0) = sv_newmortal();
+ sv_setref_pv(ST(0), "Client", (void*)RETVAL);
+ }
+ XSRETURN(1);
+}
+
#ifdef __cplusplus
extern "C"
#endif
@@ -613,6 +649,7 @@
newXSproto(strcpy(buf, "GetHighestLevel"), XS_Group_GetHighestLevel, file, "$");
newXSproto(strcpy(buf, "TeleportGroup"), XS_Group_TeleportGroup, file, "$$$$$$$");
newXSproto(strcpy(buf, "GetID"), XS_Group_GetID, file, "$");
+ newXSproto(strcpy(buf, "GetMember"), XS_Group_GetMember, file, "$");
XSRETURN_YES;
}
Index: zone/perl_questitem.cpp
================================================== =================
--- zone/perl_questitem.cpp (revision 0)
+++ zone/perl_questitem.cpp (revision 0)
@@ -0,0 +1,145 @@
+/* EQEMu: Everquest Server Emulator
+ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY except by those people which sell it, which
+ are required to give you total support for your newly bought product;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "features.h"
+#include "client.h"
+#ifdef EMBPERL_XS_CLASSES
+#include "../common/debug.h"
+#include "embperl.h"
+
+#include "../common/item.h"
+
+#ifdef THIS /* this macro seems to leak out on some systems */
+#undef THIS
+#endif
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+XS(XS_QuestItem_GetName);
+XS(XS_QuestItem_GetName) {
+ dXSARGS;
+ if (items != 1)
+ Perl_croak(aTHX_ "Usage: QuestItem::GetLastName(THIS)");
+ {
+ ItemInst * THIS;
+ Const_char * RETVAL;
+ dXSTARG;
+
+ if (sv_derived_from(ST(0), "QuestItem")) {
+ IV tmp = SvIV((SV*)SvRV(ST(0)));
+ THIS = INT2PTR(ItemInst *,tmp);
+ }
+ else
+ Perl_croak(aTHX_ "THIS is not of type ItemInst");
+ if(THIS == NULL)
+ Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
+
+ RETVAL = THIS->GetItem()->Name;
+ sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
+ }
+ XSRETURN(1);
+}
+
+XS(XS_QuestItem_SetScale);
+XS(XS_QuestItem_SetScale)
+{
+ dXSARGS;
+ if (items != 2)
+ Perl_croak(aTHX_ "Usage: QuestItem::GetID(THIS, scale factor)");
+ {
+ ItemInst * THIS;
+ float Mult;
+
+ if (sv_derived_from(ST(0), "QuestItem")) {
+ IV tmp = SvIV((SV*)SvRV(ST(0)));
+ THIS = INT2PTR(ItemInst *,tmp);
+ }
+ else
+ Perl_croak(aTHX_ "THIS is not of type ItemInst");
+ if(THIS == NULL)
+ Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
+
+ Mult = (float)SvNV(ST(1));
+
+ if(THIS->IsScaling()) {
+ ((EvoItemInst*)THIS)->SetExp((int)(Mult*10000+.5));
+ }
+ }
+ XSRETURN_EMPTY;
+}
+
+XS(XS_QuestItem_ItemSay);
+XS(XS_QuestItem_ItemSay)
+{
+ dXSARGS;
+ if (items != 2 && items != 3)
+ Perl_croak(aTHX_ "Usage: QuestItem::ItemSay(THIS, text [, language])");
+ {
+ ItemInst* THIS;
+ Const_char* text;
+ int lang = 0;
+
+ if (sv_derived_from(ST(0), "QuestItem")) {
+ IV tmp = SvIV((SV*)SvRV(ST(0)));
+ THIS = INT2PTR(ItemInst *,tmp);
+ }
+ else
+ Perl_croak(aTHX_ "THIS is not of type ItemInst");
+ if(THIS == NULL)
+ Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
+
+ text = SvPV_nolen(ST(1));
+ if(items == 3)
+ lang = (int)SvUV(ST(2));
+
+ quest_manager.GetInitiator()->ChannelMessageSend(THIS->GetItem()->Name, 0, 8, lang, 100, text);
+ }
+ XSRETURN_EMPTY;
+}
+
+
+
+
+
+XS(boot_QuestItem);
+XS(boot_QuestItem)
+{
+ dXSARGS;
+ char file[256];
+ strncpy(file, __FILE__, 256);
+ file[255] = 0;
+
+ if(items != 1)
+ fprintf(stderr, "boot_quest does not take any arguments.");
+ char buf[128];
+
+ //add the strcpy stuff to get rid of const warnings....
+
+ XS_VERSION_BOOTCHECK ;
+
+ newXSproto(strcpy(buf, "GetName"), XS_QuestItem_GetName, file, "$");
+ newXSproto(strcpy(buf, "SetScale"), XS_QuestItem_SetScale, file, "$");
+ newXSproto(strcpy(buf, "ItemSay"), XS_QuestItem_ItemSay, file, "$");
+
+ XSRETURN_YES;
+}
+
+#endif //EMBPERL_XS_CLASSES
Index: zone/perlparser.cpp
================================================== =================
--- zone/perlparser.cpp (revision 637)
+++ zone/perlparser.cpp (working copy)
@@ -41,7 +41,7 @@
*/
PerlXSParser::PerlXSParser() : PerlembParser() {
- //we cannot rely on PerlembParser to call the rigth map_funs because
+ //we cannot rely on PerlembParser to call the right map_funs because
//our virtual table is not set up until after we call them, so we need to move
//the call to ReloadQuests out of the constructor.
}
@@ -83,22 +83,25 @@
"package Raid;"
"&boot_Raid;" //load our Raid XS
+
+ "package QuestItem;"
+ "&boot_QuestItem;" // load quest item XS
#endif
"package main;"
"}"
);//eval
}
-void PerlXSParser::SendCommands(const char * pkgprefix, const char *event, int32 npcid, Mob* other, Mob* mob)
+void PerlXSParser::SendCommands(const char * pkgprefix, const char *event, int32 npcid, Mob* other, Mob* mob, ItemInst* iteminst)
{
if(!perl)
return;
_ZP(PerlXSParser_SendCommands);
if(mob && mob->IsClient())
- quest_manager.StartQuest(other, mob->CastToClient());
+ quest_manager.StartQuest(other, mob->CastToClient(), iteminst);
else
- quest_manager.StartQuest(other, NULL);
+ quest_manager.StartQuest(other, NULL, NULL);
try {
@@ -127,6 +130,14 @@
sv_setref_pv(npc, "NPC", curn);
}
+ //only export QuestItem if it's an item quest
+ if(iteminst) {
+ ItemInst* curi = quest_manager.GetQuestItem();
+ snprintf(namebuf, 64, "%s::questitem", pkgprefix);
+ SV *questitem = get_sv(namebuf, true);
+ sv_setref_pv(questitem, "QuestItem", curi);
+ }
+
snprintf(namebuf, 64, "%s::entity_list", pkgprefix);
SV *el = get_sv(namebuf, true);
sv_setref_pv(el, "EntityList", &entity_list);
@@ -203,6 +214,24 @@
XSRETURN(1);
}
+//Any creation of new quest items gets the current quest item
+XS(XS_QuestItem_new);
+XS(XS_QuestItem_new)
+{
+ dXSARGS;
+ if (items != 1)
+ Perl_croak(aTHX_ "Usage: QuestItem::new()");
+
+ ItemInst* RETVAL;
+
+ RETVAL = quest_manager.GetQuestItem();
+ ST(0) = sv_newmortal();
+ if(RETVAL)
+ sv_setref_pv(ST(0), "QuestItem", (void*)RETVAL);
+
+ XSRETURN(1);
+}
+
#endif //EMBPERL_XS_CLASSES
Index: zone/perlparser.h
================================================== =================
--- zone/perlparser.h (revision 637)
+++ zone/perlparser.h (working copy)
@@ -32,7 +32,7 @@
PerlXSParser();
// ~PerlXSParser();
- virtual void SendCommands(const char * pkgprefix, const char *event, int32 npcid, Mob* other, Mob* mob);
+ virtual void SendCommands(const char * pkgprefix, const char *event, int32 npcid, Mob* other, Mob* mob, ItemInst* iteminst);
protected:
void map_funs();
Index: zone/questmgr.cpp
================================================== =================
--- zone/questmgr.cpp (revision 637)
+++ zone/questmgr.cpp (working copy)
@@ -157,10 +157,11 @@
}
}
-void QuestManager::StartQuest(Mob *_owner, Client *_initiator) {
+void QuestManager::StartQuest(Mob *_owner, Client *_initiator, ItemInst* _questitem) {
quest_mutex.lock();
owner = _owner;
initiator = _initiator;
+ questitem = _questitem;
depop_npc = false;
}
Index: zone/questmgr.h
================================================== =================
--- zone/questmgr.h (revision 637)
+++ zone/questmgr.h (working copy)
@@ -34,7 +34,7 @@
QuestManager();
virtual ~QuestManager();
- void StartQuest(Mob *_owner, Client *_initiator = NULL);
+ void StartQuest(Mob *_owner, Client *_initiator = NULL, ItemInst* _questitem = NULL);
void EndQuest();
void Process();
@@ -215,11 +215,13 @@
inline Client *GetInitiator() const { return(initiator); }
inline NPC *GetNPC() const { return(owner->IsNPC()?owner->CastToNPC():NULL); }
inline Mob *GetOwner() const { return(owner); }
+ inline ItemInst *GetQuestItem() const {return questitem; }
inline bool ProximitySayInUse() { return HaveProximitySays; }
protected:
Mob *owner; //NPC is never NULL when functions are called.
Client *initiator; //this can be null.
+ ItemInst* questitem; // this is usually NULL.
bool depop_npc; //true if EndQuest should depop the NPC
Index: zone/spells.cpp
================================================== =================
--- zone/spells.cpp (revision 637)
+++ zone/spells.cpp (working copy)
@@ -1047,7 +1047,7 @@
if( ((PerlembParser*)parse)->PlayerHasQuestSub("EVENT_CAST") ) {
char temp[64];
sprintf(temp, "%d", spell_id);
- ((PerlembParser*)parse)->Event(EVENT_CAST, 0, temp, NULL, this->CastToClient());
+ ((PerlembParser*)parse)->Event(EVENT_CAST, 0, temp, (NPC*)NULL, this->CastToClient());
}
#endif
}
Index: zone/Zone.vcproj
================================================== =================
--- zone/Zone.vcproj (revision 637)
+++ zone/Zone.vcproj (working copy)
@@ -575,6 +575,10 @@
>
</File>
<File
+ RelativePath=".\perl_questitem.cpp"
+ >
+ </File>
+ <File
RelativePath=".\perl_raids.cpp"
>
</File>
And here's some example item files. Two of them use new quest commands that are also in the diff above.
Charm of the Emerald Warrior (CHRMEmeraldWarrior.pl):
sub EVENT_SCALE_CALC {
# Charm of the Emerald Warrior: scales with Emerald Warriors faction
# get faction level with the Emerald Warriors
my $scale = $client->GetModCharacterFactionLevel(92);
# set the scale based on where faction is in the range [0, 1500]
if($scale < 0) {
$scale = 0;
}
$questitem->SetScale($scale/1500);
}
Charm of Exotic Speech (CHRMRareLang.pl)
sub EVENT_SCALE_CALC {
# Used for charms that scale with number of rare languages learned
my $langmastered = 0;
#check each rare language: Old Erudian through Elder Dragon
for (my $i = 11; $i <= 22; $i++) {
if($client->GetLanguageSkill($i) == 100) {
$langmastered++;
}
}
$questitem->SetScale($langmastered/12);
}
Charm of the Brotherhood (CHRMBrotherhood.pl)
sub EVENT_SCALE_CALC {
#Charm of the Brotherhood: improves when group members are same race or class
my $playerrace = $client->GetRace();
my $playerclass = $client->GetClass();
my $group = $client->GetGroup();
my $member;
my $matchcount = 1;
# cycle through all group members
if($group) {
for(my $i = 1; $i < 6; $i++) {
$member = $group->GetMember($i);
if($member) {
# look for race/class that matches the player
if(($member->GetClass() == $playerclass) || ($member->GetRace() == $playerrace)) {
$matchcount++;
}
}
}
}
$questitem->SetScale($matchcount);
}
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.