rendered paste bodyIndex: src/server/adminmanager.h===================================================================--- src/server/adminmanager.h (revision 5682)+++ src/server/adminmanager.h (working copy)@@ -51,6 +51,7 @@ class psAdminGameEvent; class psNPCDialog; class psItem;+class psSkillInfo; struct Result; class iResultSet; class Client;@@ -75,6 +76,37 @@ GM_TESTER = 10 }; +/// Reward Data holds values for all kinds of rewards+struct psRewardData+{+ int expDelta; ///< relative value to adjust exp by++ csString factionName; ///< name of the faction to adjust+ int factionDelta; ///< relative value to adjust faction by++ /** name of the skill to adjust.+ * may be "all" to adjust all skills.+ * may be "copy" to set the values of the target+ */+ csString skillName;+ int skillDelta; ///< value to adjust the skill by/set it to+ unsigned int skillCap; ///< maximum value the skill should have+ + /** determines whether the value to adjust the skill is relative or not */+ bool relativeSkill;++ csString moneyType; ///< name of the money type to award (circles, hexas, ...)+ /** relativ amount of money to adjust by+ * if this is 0, a random value is used+ */+ int moneyCount;++ csString itemName; ///< name of the item to award+ unsigned short stackCount; ///< number of items to award+ + psRewardData();+};+ /** Admin manager that handles GM commands and general game control. */ class AdminManager : public MessageManager@@ -97,11 +129,41 @@ * admin commands they should have for their level. * */- void AdminCreateNewNPC(csString& data); - void AwardExperienceToTarget(int gmClientnum, Client* target, csString recipient, int ppAward);+ /** This awards a certain amount of exp to the target.+ * @param gmClientnum ClientID of the issuer+ * @oaram target pointer to the Client of the target+ * @param ppAward amount of exp to award. might be negative to punish instead+ */+ void AwardExperienceToTarget(int gmClientnum, Client* target, int ppAward);+ + /** adjusts a faction standing of the target by a given value.+ * @param gmClientnum ClientID of the issuer+ * @param target pointer to the Client of the target+ * @param factionName name of the faction to adjust+ * @param standingDelta value to adjust the standing by+ */ void AdjustFactionStandingOfTarget(int gmClientnum, Client* target, csString factionName, int standingDelta);+ + /** adjusts a skill of the target by a given value.+ * @param gmClientnum ClientID of the issuer+ * @param target pointer to the Client of the target+ * @param skill pointer to the info about the skill to adjust+ * @param value amount to set/adjust by+ * @param relative determines whether the value is absolute or relative+ * @param cap if nonzero the skill will be set to a value smaller or equal to the specified one+ * @return bool FALSE if an error occured+ */+ bool ApplySkill(int gmClientNum, Client* target, psSkillInfo* skill, int value, bool relative = false, unsigned int cap = 0);+ + /** universal function to award a target.+ * @param gmClientNum ClientID of the issuer+ * @param target pointer to the Client of the target+ * @param data struct holding the awards to apply+ * @see psRewardData+ */+ void AwardToTarget(int gmClientNum, Client* target, psRewardData& data); /** Get sector and coordinates of starting point of a map. Returns success. */ bool GetStartOfMap(int clientnum, const csString & map, iSector * & targetSector, csVector3 & targetPoint);@@ -128,7 +190,7 @@ csString type,name; ///< Used by: /location csString sourceplayer; - int value, interval, random;+ int value, value2, interval, random; int rainDrops, density, fade; unsigned int mins, hours, days; float amt, x, y, z, rot;@@ -348,6 +410,9 @@ /** Awards experience to a player, by a GM */ void AwardExperience(MsgEntry* me, psAdminCmdMessage& msg, AdminCmdData& data, Client* client, Client* target);+ + /** Awards something to a player, by a GM */+ void Award(AdminCmdData& data, Client* client, Client* target); /** Transfers an item from one client to another */ void TransferItem(MsgEntry* me, psAdminCmdMessage& msg, AdminCmdData& data, Client* source, Client* target);Index: src/server/adminmanager.cpp===================================================================--- src/server/adminmanager.cpp (revision 5682)+++ src/server/adminmanager.cpp (working copy)@@ -91,6 +91,17 @@ //----------------------------------------------------------------------------- +psRewardData::psRewardData()+{+ expDelta = 0;+ factionDelta = 0;+ skillDelta = 0;+ skillCap = 0;+ relativeSkill = false;+ moneyCount = 0;+ stackCount = 0;+}+ /** This class asks user to confirm that he really wants to do the area target he/she requested */ class AreaTargetConfirm : public PendingQuestion {@@ -484,6 +495,74 @@ } return true; }+ else if (command == "/award")+ {+ // use standard targeting+ player = words[1];++ if (words.GetCount() < 4)+ {+ // invalid arguments+ help = true;+ return true;+ }+ + // initialize PODs+ value = 0;+ stackCount = 0;+ value2 = 0;+ interval = 0;+ random = 0;+ density = 0;+ + size_t index = 2;+ size_t left;+ // doesn't include a check for duplicate award types+ while (index < words.GetCount()) // retrieve award types and values+ {+ subCmd = words[index++];+ left = words.GetCount() - index;+ if (subCmd == "exp" && left >= 1)+ {+ value = words.GetInt(index++);+ }+ else if (subCmd == "item" && left >= 2)+ {+ stackCount = words.GetInt(index++);+ item = words[index++];+ }+ else if (subCmd == "skill" && left >= 2)+ {+ skill = words[index++];++ // check for relative value+ if (words[index][0] == '+' || words[index][0] == '-')+ insert = true;+ value2 = words.GetInt(index++);++ // check for optional maximum+ interval = words.GetInt(index);+ if (interval)+ index++;+ }+ else if (subCmd == "money" && left >= 2)+ {+ type = words[index++];+ random = words.GetInt(index++);+ }+ else if (subCmd == "faction" && left >= 2)+ {+ name = words[index++];+ density = words.GetInt(index++);+ }+ else // invalid arguments+ {+ help = true;+ break;+ }+ }+ return true;+ } else if (command == "/checkitem" ) { player = words[1];@@ -673,12 +752,19 @@ } else {+ if (words[3][0] == '+' || words[3][0] == '-')+ insert = true; value = words.GetInt(3);+ + if (words.GetCount() >= 5)+ interval = words.GetInt(4);+ else+ interval = 0; } } else {- value = -2;+ help = true; } return true; }@@ -916,56 +1002,91 @@ } else if (subCmd == "reward") {- // "/event reward [range # | all | [player_name]] <#> item"- int rewardIndex = 3;- stackCount = 0;+ size_t index = 3; - if (strspn(words[2].GetDataSafe(), "-0123456789") == words[2].Length())+ // retrieve the target type+ if (words[2] == "target") {- commandMod.Empty();- stackCount = words.GetInt(2);- rangeSpecifier = INDIVIDUAL; // expecting a player by target+ rangeSpecifier = INDIVIDUAL; }+ else if (words[2] == "all")+ {+ commandMod = "all";+ rangeSpecifier = ALL;+ }+ else if (words[2] == "range")+ {+ commandMod = "range";+ rangeSpecifier = IN_RANGE;+ range = words.GetFloat(index++);+ } else {- commandMod = words[2]; // 'range' or 'all'- range = 0;- if (commandMod == "range")+ rangeSpecifier = INDIVIDUAL;+ player = words[2];+ }+ + size_t left = words.GetCount() - index;+ if (left < 2) // invalid arguments+ {+ subCmd = "help";+ help = true;+ }+ + // initialize PODs+ value = 0;+ stackCount = 0;+ value2 = 0;+ interval = 0;+ random = 0;+ density = 0;+ + // doesn't include a check for duplicate award types+ while (index < words.GetCount() && !help) // retrieve award types and values+ {+ subCmd = words[index++];+ left = words.GetCount() - index;+ if (subCmd == "exp" && left >= 1) {- rangeSpecifier = IN_RANGE;- if (strspn(words[3].GetDataSafe(), "0123456789.") == words[3].Length())- {- range = words.GetFloat(3);- rewardIndex = 4;- }+ value = words.GetInt(index++); }- else if (commandMod == "all")+ else if (subCmd == "item" && left >= 2) {- rangeSpecifier = ALL;+ stackCount = words.GetInt(index++);+ item = words[index++]; }- else+ else if (subCmd == "skill" && left >= 2) {- rangeSpecifier = INDIVIDUAL;- player = words[2];- commandMod.Empty();+ skill = words[index++];++ // check for relative value+ if (words[index][0] == '+' || words[index][0] == '-')+ insert = true;+ value2 = words.GetInt(index++);++ // check for optional maximum+ interval = words.GetInt(index);+ if (interval)+ index++; }-- // next 'word' should be numeric: number of items.- if (strspn(words[rewardIndex].GetDataSafe(), "-0123456789") == words[rewardIndex].Length())+ else if (subCmd == "money" && left >= 2) {- stackCount = words.GetInt(rewardIndex);- rewardIndex++;+ type = words[index++];+ random = words.GetInt(index++); }- else+ else if (subCmd == "faction" && left >= 2) {+ name = words[index++];+ density = words.GetInt(index++);+ }+ else // invalid arguments+ { subCmd = "help"; help = true;- return true; } }-- // last bit is the item name itself!- item = words.GetTail(rewardIndex);+ + subCmd = "reward"; } else if (subCmd == "remove") {@@ -1397,6 +1518,10 @@ { TransferItem(me, msg, data, targetclient, client); }+ else if (data.command == "/award" )+ {+ Award(data, client, targetclient);+ } else if (data.command == "/checkitem" ) { CheckItem(me, msg, data, targetclient);@@ -4107,42 +4232,13 @@ void AdminManager::CreateMoney(MsgEntry* me, psAdminCmdMessage& msg, AdminCmdData& data,Client *client) {- bool valid = true;- Money_Slots type;+ psRewardData rewardData;+ rewardData.moneyType = data.item;+ rewardData.moneyCount = data.value;+ if (data.random)+ rewardData.moneyCount = 0; - if(data.item == "trias")- type = MONEY_TRIAS;- else if(data.item == "hexas")- type = MONEY_HEXAS;- else if(data.item == "octas")- type = MONEY_OCTAS;- else if(data.item == "circles")- type = MONEY_CIRCLES;- else- valid = false;-- if (!valid || (data.value == 0 && data.random == 0))- {- psserver->SendSystemError(me->clientnum, "Syntax: /money <circles|hexas|octas|trias> <random|quantity>");- return;- }--- psCharacter* charData = client->GetCharacterData();-- int quantity = data.value;- if(data.random > 0)- quantity = psserver->rng->Get(1000) + 1;-- psMoney money;-- money.Set(type, quantity);-- Debug4(LOG_ADMIN,me->clientnum, "Created %d %s for %s\n", quantity, data.item.GetDataSafe(), charData->GetCharName());-- charData->AdjustMoney(money, false);- psserver->GetCharManager()->SendPlayerMoney(client);-+ AwardToTarget(client->GetClientNum(), client, rewardData); } void AdminManager::RunScript(MsgEntry *me, psAdminCmdMessage& msg, AdminCmdData& data,Client *client, gemObject* object)@@ -6255,24 +6351,193 @@ psserver->GetCharManager()->UpdateItemViews(me->clientnum); } -void AdminManager::AwardExperience(MsgEntry* me, psAdminCmdMessage& msg, AdminCmdData& data, Client* client, Client* target)+void AdminManager::Award(AdminCmdData& data, Client* client, Client* target) {+ if (data.help)+ {+ psserver->SendSystemInfo(client->GetClientNum(), "Syntax: \"/award <area:[players]:range|me|target|player|eid:EID|pid:PID>\n"+ "['exp' value] ['item' count item] ['skill' <skill|'all'> [+-]value [max]]\n"+ "['money' <circles|hexas|octas|trias> <value|'random'>] ['faction' faction value]\"");+ return;+ }++ // unpack arguments+ psRewardData rewardData;+ rewardData.expDelta = data.value;+ rewardData.itemName = data.item;+ rewardData.stackCount = data.stackCount;+ rewardData.factionName = data.name;+ rewardData.factionDelta = data.density;+ rewardData.skillName = data.skill;+ rewardData.skillDelta = data.value2;+ rewardData.skillCap = data.interval;+ rewardData.relativeSkill = data.insert;+ rewardData.moneyType = data.type;+ rewardData.moneyCount = data.random;+ + AwardToTarget(client->GetClientNum(), target, rewardData);+}++void AdminManager::AwardToTarget(int gmClientNum, Client* target, psRewardData& data)+{ if (!target || !target->GetCharacterData()) {- psserver->SendSystemError(me->clientnum, "Invalid target to award experience to");+ psserver->SendSystemError(gmClientNum, "Invalid target to award"); return; } + psCharacter * pchar = target->GetCharacterData();+ if (pchar->IsNPC())+ {+ psserver->SendSystemError(gmClientNum, "You can't use this command on npcs!");+ return;+ }++ if (data.expDelta) // award exp+ {+ AwardExperienceToTarget(gmClientNum, target, data.expDelta);+ }++ if (data.itemName && data.stackCount) // award item+ {+ csString text;+ psItemStats* stats = CacheManager::GetSingleton().GetBasicItemStatsByName(data.itemName);+ if (!stats)+ {+ psserver->SendSystemError(gmClientNum, "You have to specify a valid item name");+ }+ else if (stats->IsMoney())+ {+ psserver->SendSystemError(gmClientNum, "Use the 'money' award to award money, not the 'item' one.");+ }+ else if (stats->GetBuyPersonalise())+ {+ psserver->SendSystemError(gmClientNum, "You cannot award personalized items.");+ }+ else if (data.stackCount > MAX_STACK_COUNT)+ {+ text.Format("The value for the stackCount has to be between 0 and %u", MAX_STACK_COUNT);+ psserver->SendSystemError(gmClientNum, text);+ }+ else // eveyrthing alright - create item+ {+ psItem* item = stats->InstantiateBasicItem(true);+ item->SetStackCount(data.stackCount);+ item->SetItemQuality(stats->GetQuality());+ item->SetLoaded();+ pchar->Inventory().AddOrDrop(item);+ psserver->GetCharManager()->UpdateItemViews(target->GetClientNum());++ // notify target+ text.Format("You have been awarded %d %s.", data.stackCount, data.itemName.GetDataSafe());+ psserver->SendSystemInfo(target->GetClientNum(), text);++ if (gmClientNum != target->GetClientNum()) // notify issuer+ {+ text.Format("%s has been awarded %d %s.", target->GetName(), data.stackCount, data.itemName.GetDataSafe());+ psserver->SendSystemInfo(gmClientNum, text);+ }++ Debug4(LOG_ADMIN, gmClientNum, "Created %d %s for %s\n", data.stackCount, data.itemName.GetDataSafe(), target->GetName());+ }+ }++ if (data.factionName && data.factionDelta) // award faction+ {+ AdjustFactionStandingOfTarget(gmClientNum, target, data.factionName, data.factionDelta);+ }++ if (data.skillName) // award skill+ {+ bool modified = false;+ if (data.skillName == "all") // update all skills+ {+ for (int i=0; i<PSSKILL_COUNT; i++)+ {+ psSkillInfo* skill = CacheManager::GetSingleton().GetSkillByID(i);+ if (!skill) continue; // skill doesn't exist -> this should not happen+ modified |= ApplySkill(gmClientNum, target, skill, data.skillDelta, data.relativeSkill, data.skillCap);+ }+ }+ else // update a certain one+ {+ psSkillInfo* skill = CacheManager::GetSingleton().GetSkillByName(data.skillName);+ modified |= ApplySkill(gmClientNum, target, skill, data.skillDelta, data.relativeSkill, data.skillCap);+ }++ if (modified && target) // update client view if we changed something+ {+ psserver->GetProgressionManager()->SendSkillList(target, false);+ }+ }++ if (data.moneyType) // award money+ {+ bool valid = true;+ + // determine money type+ Money_Slots type;+ if(data.moneyType == "trias")+ type = MONEY_TRIAS;+ else if(data.moneyType == "hexas")+ type = MONEY_HEXAS;+ else if(data.moneyType == "octas")+ type = MONEY_OCTAS;+ else if(data.moneyType == "circles")+ type = MONEY_CIRCLES;+ else+ valid = false;+ + if (valid)+ {+ int value;+ if (data.moneyCount) // fixed amount+ value = data.moneyCount;+ else // random amount+ value = psserver->rng->Get(1000)+1;+ psMoney money;+ money.Set(type, value);+ pchar->AdjustMoney(money, false);++ // update client view+ psserver->GetCharManager()->SendPlayerMoney(target);++ // notify target+ csString text;+ text.Format("You have been awarded %d %s.", value, data.moneyType.GetDataSafe());+ psserver->SendSystemInfo(target->GetClientNum(), text);++ if (gmClientNum != target->GetClientNum()) // notify issuer+ {+ text.Format("%s has been awarded %d %s.", target->GetName(), value, data.moneyType.GetDataSafe());+ psserver->SendSystemInfo(gmClientNum, text);+ }+ + Debug4(LOG_ADMIN, gmClientNum, "Created %d %s for %s\n", value, data.moneyType.GetDataSafe(), pchar->GetCharName());+ }+ else+ {+ psserver->SendSystemError(gmClientNum, "Invalid money type");+ }+ }+}++void AdminManager::AwardExperience(MsgEntry* me, psAdminCmdMessage& msg, AdminCmdData& data, Client* client, Client* target)+{ if (data.value == 0) { psserver->SendSystemError(me->clientnum, "Invalid experience specified"); return; } - AwardExperienceToTarget(me->clientnum, target, data.player, data.value);+ // unpack argument+ psRewardData rewardData;+ rewardData.expDelta = data.value;++ AwardToTarget(me->clientnum, target, rewardData); } -void AdminManager::AwardExperienceToTarget(int gmClientnum, Client* target, csString recipient, int ppAward)+void AdminManager::AwardExperienceToTarget(int gmClientnum, Client* target, int ppAward) { unsigned int pp = target->GetCharacterData()->GetProgressionPoints(); @@ -6310,7 +6575,7 @@ psserver->SendSystemInfo(target->GetClientNum(),"You lost %d progression points.", -ppAward); } - psserver->SendSystemInfo(gmClientnum, "You awarded %s %d progression points.", recipient.GetData(), ppAward);+ psserver->SendSystemInfo(gmClientnum, "You awarded %s %d progression points.", target->GetName(), ppAward); } void AdminManager::AdjustFactionStandingOfTarget(int gmClientnum, Client* target, csString factionName, int standingDelta)@@ -6605,70 +6870,74 @@ void AdminManager::SetSkill(MsgEntry* me, psAdminCmdMessage& msg, AdminCmdData& data, Client* client, gemActor *target) {+ if (data.skill.IsEmpty() || data.help)+ {+ psserver->SendSystemError(me->clientnum, "Syntax: /setskill [target] [skill|'all'] [+-][value] | [target] copy [source]");+ return;+ }+ + if (!target || target->GetClient() != client && !psserver->CheckAccess(client, "setskill others"))+ {+ psserver->SendSystemError(me->clientnum, "You have to specify a valid target");+ return;+ }++ if (data.skill != "copy")+ {+ psRewardData rewardData;+ rewardData.skillName = data.skill;+ rewardData.skillDelta = data.value;+ rewardData.relativeSkill = data.insert;+ rewardData.skillCap = data.interval;+ + AwardToTarget(me->clientnum, target->GetClient(), rewardData);+ return;+ }+ Client* sourceclient = NULL; gemActor* source = NULL; gemObject* sourceobject = NULL; psCharacter * schar = NULL; - // Try to find the source of skills if we're doing a copy- if (data.skill == "copy")+ // First try and find the source client by name+ if (data.sourceplayer == "me") {- // First try and find the source client by name- if (data.sourceplayer == "me")- {- sourceclient = client;- }- else- {- sourceclient = FindPlayerClient(data.sourceplayer);- }+ sourceclient = client;+ }+ else+ {+ sourceclient = FindPlayerClient(data.sourceplayer);+ } - if (sourceclient)+ if (sourceclient)+ {+ source = sourceclient->GetActor();+ }+ // If a search by name didn't work, try and search by pid or eid+ else+ {+ sourceobject = FindObjectByString(data.sourceplayer,client->GetActor());+ if (sourceobject) {- source = sourceclient->GetActor();+ source = sourceobject->GetActorPtr(); }- // If a search by name didn't work, try and search by pid or eid- else- {- sourceobject = FindObjectByString(data.sourceplayer,client->GetActor());- if (sourceobject)- {- source = sourceobject->GetActorPtr();- }- }+ } - if (source == NULL)- {- psserver->SendSystemError(me->clientnum, "Invalid skill source");- return;- }- else- {- schar = source->GetCharacterData();- if (!schar)- {- psserver->SendSystemError(me->clientnum, "No source character data!");- return;- }- }- }- // Not a copy, just proceed as normal- else if (data.skill.IsEmpty() || data.value == -2)+ if (source == NULL) {- psserver->SendSystemError(me->clientnum, "Syntax: /setskill [target] [skill|'all'] [value|-1] | [target] copy [source]");+ psserver->SendSystemError(me->clientnum, "Invalid skill source"); return; }-- if (target == NULL)+ else {- psserver->SendSystemError(me->clientnum, "Invalid target for setting skills");- return;+ schar = source->GetCharacterData();+ if (!schar)+ {+ psserver->SendSystemError(me->clientnum, "No source character data!");+ return;+ } } - // Check the permission to set skills for other characters- if (target->GetClient() != client && !psserver->CheckAccess(client, "setskill others"))- return;- psCharacter * pchar = target->GetCharacterData(); if (!pchar) {@@ -6682,176 +6951,92 @@ return; } - // use unsigned int since skills are never negative (this also takes care of overflows)- unsigned int value = data.value;- unsigned int max = MAX(MAX_SKILL, MAX_STAT);- if (data.skill == "all")+ bool modified = false;+ for (int i=0; i<PSSKILL_COUNT; i++) {- // if the value is out of range, send an error- if (data.value != -1 && (value < 0 || value > max))- {- psserver->SendSystemError(me->clientnum, "Valid values are between 0 and %u", max);- return;- }+ psSkillInfo * skill = CacheManager::GetSingleton().GetSkillByID(i);+ if (skill == NULL) continue;+ modified |= ApplySkill(me->clientnum, target->GetClient(), skill, schar->Skills().GetSkillRank(skill->id).Current());+ } - for (int i=0; i<PSSKILL_COUNT; i++)- {- psSkillInfo * skill = CacheManager::GetSingleton().GetSkillByID(i);- if (skill == NULL) continue;+ // Send updated skill list to client+ if(modified && target->GetClient())+ psserver->GetProgressionManager()->SendSkillList(target->GetClient(), false);+} - unsigned int old_value = pchar->Skills().GetSkillRank(skill->id).Current();-- if(data.value == -1)- {- PSITEMSTATS_STAT stat = skillToStat(skill->id);- if (stat != PSITEMSTATS_STAT_NONE)- {- //Handle stats differently to pickup buffs/debuffs- int base = pchar->Stats()[stat].Base();- int current = pchar->Stats()[stat].Current();- if (base == current)- psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %u", skill->name.GetDataSafe(), target->GetName(), base);- else- psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %u (%u)", skill->name.GetDataSafe(), target->GetName(), base, current);- } else {- int base = pchar->Skills().GetSkillRank(skill->id).Base();- int current = pchar->Skills().GetSkillRank(skill->id).Current();- if (base == current)- psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %u", skill->name.GetDataSafe(), target->GetName(), base);- else- psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %u (%u)", skill->name.GetDataSafe(), target->GetName(), base, current);- }- }- else- {- pchar->SetSkillRank(skill->id, value);- psserver->SendSystemInfo(me->clientnum, "Changed '%s' of '%s' from %u to %u", skill->name.GetDataSafe(), target->GetName(), old_value,data.value);- }- }-- if(data.value != -1)- return;-- if (target->GetClient() && target->GetClient() != client)- {- // Inform the other player.- psserver->SendSystemOK(target->GetClientID(), "All your skills were set to %d by a GM", data.value);- }- }- else if (data.skill == "copy")+bool AdminManager::ApplySkill(int client, Client* target, psSkillInfo* skill, int value, bool relative, unsigned int cap)+{+ // perform sanity checks+ if (!skill) {- for (int i=0; i<PSSKILL_COUNT; i++)- {- psSkillInfo * skill = CacheManager::GetSingleton().GetSkillByID(i);- if (skill == NULL) continue;-- unsigned int old_value = pchar->Skills().GetSkillRank(skill->id).Current();- unsigned int new_value = schar->Skills().GetSkillRank(skill->id).Current();-- pchar->SetSkillRank(skill->id, new_value);- psserver->SendSystemInfo(me->clientnum, "Changed '%s' of '%s' from %u to %u", skill->name.GetDataSafe(), target->GetName(), old_value, new_value);-- if (target->GetClient() && target->GetClient() != client)- {- // Inform the other player.- psserver->SendSystemOK(target->GetClientID(), "Your '%s' level was set to %d by a GM", data.skill.GetDataSafe(), new_value);- }- }+ psserver->SendSystemError(client, "Invalid Skill");+ return false; }- else+ + if (!target || !client) // no target or issuer+ return false;+ + psCharacter * pchar = target->GetCharacterData();+ + if (!pchar) // target is no player+ return false;+ + if (relative && !value) // +0 or -0: show current status and return {- psSkillInfo * skill = CacheManager::GetSingleton().GetSkillByName(data.skill);- if (skill == NULL)+ int base, current;+ if (skill->category == PSSKILLS_CATEGORY_STATS) // handle stats explicitly {- psserver->SendSystemError(me->clientnum, "Skill not found");- return;- }-- unsigned int old_value = pchar->Skills().GetSkillRank(skill->id).Current();- if (data.value == -1)- { PSITEMSTATS_STAT stat = skillToStat(skill->id);- if (stat != PSITEMSTATS_STAT_NONE)- {- //Handle stats differently to pickup buffs/debuffs- int base = pchar->Stats()[stat].Base();- int current = pchar->Stats()[stat].Current();- if (base == current)- psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %u", skill->name.GetDataSafe(), target->GetName(), base);- else- psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %u (%u)", skill->name.GetDataSafe(), target->GetName(), base, current);- } else {- int base = pchar->Skills().GetSkillRank(skill->id).Base();- int current = pchar->Skills().GetSkillRank(skill->id).Current();- if (base == current)- psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %u", skill->name.GetDataSafe(), target->GetName(), base);- else- psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %u (%u)", skill->name.GetDataSafe(), target->GetName(), base, current);- }- return;+ base = pchar->Stats()[stat].Base();+ current = pchar->Stats()[stat].Current(); }- else if (skill->category == PSSKILLS_CATEGORY_STATS && (value < 0 || value > MAX_STAT))+ else {- psserver->SendSystemError(me->clientnum, "Stat values are between 0 and %u", MAX_STAT);- return;+ base = pchar->Skills().GetSkillRank(skill->id).Base();+ current = pchar->Skills().GetSkillRank(skill->id).Current(); }- else if (skill->category != PSSKILLS_CATEGORY_STATS && (value < 0 || value > MAX_SKILL))- {- psserver->SendSystemError(me->clientnum, "Skill values are between 0 and %u", MAX_SKILL);- return;- } - pchar->SetSkillRank(skill->id, value);- psserver->SendSystemInfo(me->clientnum, "Changed '%s' of '%s' from %u to %u", skill->name.GetDataSafe(), target->GetName(), old_value,data.value);-- if (target->GetClient() && target->GetClient() != client)- {- // Inform the other player.- psserver->SendSystemOK(target->GetClientID(), "Your '%s' level was set to %d by a GM", data.skill.GetDataSafe(), data.value);- }+ // notify issuer+ if (base == current)+ psserver->SendSystemInfo(client, "Current '%s' of '%s' is %d", skill->name.GetDataSafe(), target->GetName(), base);+ else+ psserver->SendSystemInfo(client, "Current '%s' of '%s' is %d (%d)", skill->name.GetDataSafe(), target->GetName(), base, current);+ + return false; }-- // Send updated skill list to client- if(target->GetClient())- psserver->GetProgressionManager()->SendSkillList(target->GetClient(), false);-}-/*-void AdminManager::AwardSkillToTarget(int gmClientnum, Client* target, csSring skillName, csString recipient, int levelAward, int limit, bool relative)-{- psCharacter* charData = player->GetCharacterData();- unsigned int value = abs(data.value);- unsigned int max = MAX(MAX_SKILL, MAX_STAT);- - if(skillName == "all")+ else // modify skill {+ int old_value = pchar->Skills().GetSkillRank(skill->id).Current(); // backup current value+ int new_value = value;+ int max = MAX_SKILL; - }- else- {- psSkillInfo * skill = CacheManager::GetSingleton().GetSkillByName(skillName);- if (skill == NULL)- {- psserver->SendSystemError(me->clientnum, "Skill not found");- return;- }- unsigned int oldValue = charData->Skills().GetSkillRank(skill->id).Current();- charData->SetSkillRank(skill->id, value);- psserver->SendSystemInfo(me->clientnum, "Changed '%s' of '%s' from %u to %u", skill->name.GetDataSafe(), target->GetName(), old_value,data.value);+ if (relative)+ new_value += old_value; - if (target->GetClient() && target->GetClient() != client)- {- // Inform the other player.- psserver->SendSystemOK(target->GetClientID(), "Your '%s' level was set to %d by a GM", data.skill.GetDataSafe(), data.value);- }+ if (skill->category == PSSKILLS_CATEGORY_STATS) // stats have an own maximum+ max = MAX_STAT;++ if (cap && cap < max) // check whether the issuer specified a maximum+ max = cap;++ // adjust the value to be between 0 and the maximum if needed+ if (new_value > max)+ new_value = max;+ else if (new_value < 0)+ new_value = 0;++ pchar->SetSkillRank(skill->id, new_value);++ // notify issuer+ psserver->SendSystemInfo(client, "Changed '%s' of '%s' from %d to %d", skill->name.GetDataSafe(), target->GetName(), old_value, new_value);++ if (target && target->GetClientNum() != client) // notify target+ psserver->SendSystemOK(target->GetClientNum(), "Your '%s' level was set to %d by a GM", skill->name.GetDataSafe(), new_value); }-- // Send updated skill list to client- if(target->GetClient())- psserver->GetProgressionManager()->SendSkillList(target->GetClient(), false); + return true;+} -}*/- void AdminManager::UpdateRespawn(AdminCmdData& data, Client* client, gemActor* target) { if (!target)@@ -7702,7 +7887,6 @@ (data.gmeventName.Length() == 0 || data.gmeventDesc.Length() == 0)) || (data.subCmd == "register" && data.player.Length() == 0 && data.rangeSpecifier == INDIVIDUAL) || (data.subCmd == "remove" && data.player.Length() == 0) ||- (data.subCmd == "reward" && data.item.Length() == 0 && data.stackCount == 0) || (data.subCmd == "control" && data.gmeventName.Length() == 0) || (data.subCmd == "discard" && data.gmeventName.Length() == 0)) {@@ -7715,7 +7899,9 @@ psserver->SendSystemInfo( me->clientnum, "/event help\n" "/event create <name> <description>\n" "/event register [range <range> | <player>]\n"- "/event reward [all | range <range> | <player>] # <item>\n"+ "/event reward <target | all | range <range> | <player>> ['skill' <skill|'all'> [+-]value [max]]\n"+ "['exp' value] ['item' count item] ['money' <circles|hexas|octas|trias> <value|'random'>]\n"+ "['faction' faction value]\n" "/event remove <player>\n" "/event complete [<name>]\n" "/event list\n"@@ -7769,12 +7955,21 @@ // reward player(s) if (data.subCmd == "reward") {- gmeventResult = gmeventManager->RewardPlayersInGMEvent(client,- data.rangeSpecifier,- data.range,- target,- data.stackCount,- data.item);+ // unpack arguments+ psRewardData rewardData;+ rewardData.expDelta = data.value;+ rewardData.itemName = data.item;+ rewardData.stackCount = data.stackCount;+ rewardData.factionName = data.name;+ rewardData.factionDelta = data.density;+ rewardData.skillName = data.skill;+ rewardData.skillDelta = data.value2;+ rewardData.skillCap = data.interval;+ rewardData.relativeSkill = data.insert;+ rewardData.moneyType = data.type;+ rewardData.moneyCount = data.random;++ gmeventResult = gmeventManager->RewardPlayersInGMEvent(client, data.rangeSpecifier, data.range, target, rewardData); return; } @@ -8429,13 +8624,12 @@ psserver->SendSystemInfo(client->GetClientNum(),"Syntax: \"/assignfaction [me/target/eid/pid/area/name] [factionname] [points]\""); return; }- if(!target)- {- psserver->SendSystemInfo(client->GetClientNum(),"Unable to find the player to assign faction points to.");- return;- }-- AdjustFactionStandingOfTarget(client->GetClientNum(), target, data.name, data.value);+ + psRewardData rewardData;+ rewardData.factionName = data.name;+ rewardData.factionDelta = data.value;+ + AwardToTarget(me->clientnum, target, rewardData); } void AdminManager::HandleServerQuit(MsgEntry* me, psAdminCmdMessage& msg, AdminCmdData& data, Client *client )Index: src/server/gmeventmanager.cpp===================================================================--- src/server/gmeventmanager.cpp (revision 5682)+++ src/server/gmeventmanager.cpp (working copy)@@ -422,13 +422,10 @@ RangeSpecifier rewardRecipient, float range, Client* target,- short stackCount,- csString itemName)+ psRewardData& data) { GMEvent* gmEvent; int clientnum = client->GetClientNum(), zero = 0;- WordArray rewardDesc(itemName);- RewardType rewardType = REWARD_ITEM; PID gmID = client->GetPID(); // make sure GM is running (or assisting) an event@@ -450,50 +447,6 @@ return false; } - // identify reward type: experience, faction points or an item- if (rewardDesc[0] == "exp" && rewardDesc.GetCount() == 1)- rewardType = REWARD_EXPERIENCE;- else if (rewardDesc[0] == "faction" && rewardDesc.GetCount() > 1)- rewardType = REWARD_FACTION_POINTS;-- // retrieve base stats item- psItemStats *basestats;- if (rewardType == REWARD_ITEM)- {- basestats = CacheManager::GetSingleton().GetBasicItemStatsByName(itemName.GetDataSafe());- if (basestats == NULL)- {- psserver->SendSystemInfo(clientnum, "Reward \'%s\' not recognised.", itemName.GetDataSafe());- Error2("'%s' was not found as a valid base item.", itemName.GetDataSafe());- return false;- }-- if (stackCount <= 0)- {- psserver->SendSystemInfo(clientnum,- "You must reward at least 1 item to participant(s).");- return false;- }- - if (stackCount >= 65 && !basestats->IsMoney())- {- psserver->SendSystemInfo(clientnum,- "You can't reward that amount of items to partecipant(s).");- return false;- }-- // cant reward personalised or unique items- if (basestats->GetBuyPersonalise() || basestats->GetUnique())- {- psserver->SendSystemInfo(clientnum,- "You cannot reward personalised / unique items.");- return false;- }- }- else- basestats = NULL;-- if (rewardRecipient == INDIVIDUAL) { if (!target)@@ -504,12 +457,7 @@ GMEvent* playersEvent = GetGMEventByPlayer(target->GetPID(), RUNNING, zero); if (playersEvent && playersEvent->id == gmEvent->id) {- if (rewardType == REWARD_EXPERIENCE)- psserver->GetAdminManager()->AwardExperienceToTarget(clientnum, target, target->GetName(), stackCount);- else if (rewardType == REWARD_FACTION_POINTS)- psserver->GetAdminManager()->AdjustFactionStandingOfTarget(clientnum, target, rewardDesc.GetTail(1), stackCount);- else- RewardPlayer(clientnum, target, stackCount, basestats);+ psserver->GetAdminManager()->AwardToTarget(clientnum, target, data); } else {@@ -531,12 +479,7 @@ { if (rewardRecipient == ALL || clientActor->RangeTo(target->GetActor()) <= range) {- if (rewardType == REWARD_EXPERIENCE)- psserver->GetAdminManager()->AwardExperienceToTarget(clientnum, target, target->GetName(), stackCount);- else if (rewardType == REWARD_FACTION_POINTS)- psserver->GetAdminManager()->AdjustFactionStandingOfTarget(clientnum, target, rewardDesc.GetTail(1), stackCount);- else- RewardPlayer(clientnum, target, stackCount, basestats);+ psserver->GetAdminManager()->AwardToTarget(clientnum, target, data); } } }@@ -981,51 +924,6 @@ return SIZET_NOT_FOUND; } -void GMEventManager::RewardPlayer(int clientnum, Client* target, short stackCount, psItemStats* basestats)-{- // If it's money don't instantiate them just directly give them.- if(basestats->IsMoney())- {- target->GetActor()->GetCharacterData()->SetMoney(basestats, stackCount);- psserver->SendSystemInfo(target->GetClientNum(),- "You have been rewarded %d %s%s for participating in this event.",- stackCount, basestats->GetName(), (stackCount>1)?"s":"");- psserver->SendSystemInfo(clientnum, "%s has been rewarded %d %s%s.",- target->GetName(), stackCount,- basestats->GetName(), (stackCount>1)?"s":"");- return;- }-- // generate the prize item- psItem* newitem = basestats->InstantiateBasicItem(true);- if (newitem == NULL)- {- Error1("Could not instantiate from base item.");- psserver->SendSystemInfo(clientnum, "%s has not been rewarded.", target->GetName());- return;- }- newitem->SetItemQuality(basestats->GetQuality());- newitem->SetStackCount(stackCount);-- // spawn the item into the recipients inventory- newitem->SetLoaded(); // Item is fully created- if (target->GetActor()->GetCharacterData()->Inventory().Add(newitem))- {- // inform recipient of their prize- psserver->SendSystemInfo(target->GetClientNum(),- "You have been rewarded %d %s%s for participating in this event.",- stackCount, basestats->GetName(), (stackCount>1)?"s":"");- psserver->SendSystemInfo(clientnum, "%s has been rewarded %d %s%s.",- target->GetName(), stackCount,- basestats->GetName(), (stackCount>1)?"s":"");- return;- }-- // failed to stash item, so remove it- CacheManager::GetSingleton().RemoveInstance(newitem);- psserver->SendSystemInfo(clientnum, "%s has not been rewarded.", target->GetName());-}- int GMEventManager::GetNextEventID(void) { // TODO this is just too simpleIndex: src/server/database/mysql/command_access.sql===================================================================--- src/server/database/mysql/command_access.sql (revision 5682)+++ src/server/database/mysql/command_access.sql (working copy)@@ -100,6 +100,9 @@ INSERT INTO command_group_assignment VALUES( "/awardexp", 30 ); INSERT INTO command_group_assignment VALUES( "/awardexp", 25 ); INSERT INTO command_group_assignment VALUES( "/awardexp", 24 );+INSERT INTO command_group_assignment VALUES( "/award", 30 );+INSERT INTO command_group_assignment VALUES( "/award", 25 );+INSERT INTO command_group_assignment VALUES( "/award", 24 ); INSERT INTO command_group_assignment VALUES( "quest change others", 30 ); INSERT INTO command_group_assignment VALUES( "quest change others", 25 ); INSERT INTO command_group_assignment VALUES( "quest change others", 24 );Index: src/server/gmeventmanager.h===================================================================--- src/server/gmeventmanager.h (revision 5682)+++ src/server/gmeventmanager.h (working copy)@@ -44,6 +44,7 @@ #define SUPPORT_GM_LEVEL GM_LEVEL_4 class psItemStats;+class psRewardData; enum GMEventStatus {@@ -138,16 +139,14 @@ * @param rewardRecipient: who will receive the reward. * @param range: required range of winners (NO_RANGE = all participants). * @param target: specific individual winner.- * @param stackCount: number of items to reward.- * @param itemName: name of the reward item.+ * @param RewardData: struct holding the rewards. * @return bool: true = success, false = failed. */ bool RewardPlayersInGMEvent (Client* client, RangeSpecifier rewardRecipient, float range, Client *target,- short stackCount,- csString itemName);+ psRewardData& data); /** @brief Returns all events for a player. *@@ -288,21 +287,6 @@ */ void SetEvalStatus(PID PlayerID, GMEvent *Event, bool NewStatus); - /** @brief Reward player in event.- *- * @param clientnum: GM client number.- * @param target: client pointer to recipient.- * @param stackCount: stack count # items in reward.- * @param basestats: base stats of reward item.- */- void RewardPlayer(int clientnum, Client* target, short stackCount, psItemStats* basestats);- enum RewardType- {- REWARD_ITEM,- REWARD_EXPERIENCE,- REWARD_FACTION_POINTS- };- /** Get next free event id number. */ int GetNextEventID(void);