rendered paste bodyIndex: src/server/adminmanager.h===================================================================--- src/server/adminmanager.h (revision 5627)+++ 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,27 @@ GM_TESTER = 10 }; +struct psRewardData+{+ int expDelta;++ csString factionName;+ int factionDelta;++ csString skillName;+ int skillDelta;+ unsigned int skillCap;+ bool relativeSkill;++ csString moneyType;+ int moneyCount;++ csString itemName;+ unsigned short stackCount;+ + psRewardData();+};+ /** Admin manager that handles GM commands and general game control. */ class AdminManager : public MessageManager@@ -100,8 +122,10 @@ void AdminCreateNewNPC(csString& data); - void AwardExperienceToTarget(int gmClientnum, Client* target, csString recipient, int ppAward);+ void AwardExperienceToTarget(int gmClientnum, Client* target, int ppAward); void AdjustFactionStandingOfTarget(int gmClientnum, Client* target, csString factionName, int standingDelta);+ bool ApplySkill(int gmClientNum, Client* target, psSkillInfo* skill, int value, bool relative = false, unsigned int cap = 0);+ 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 +152,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 +372,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 5627)+++ 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,68 @@ } return true; }+ else if (command == "/award")+ {+ player = words[1];+ + if (words.GetCount() < 4)+ {+ 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())+ {+ 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++];+ if (words[index][0] == '+' || words[index][0] == '-')+ insert = true;+ value2 = words.GetInt(index++);+ 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+ {+ help = true;+ break;+ }+ }+ return true;+ } else if (command == "/checkitem" ) { player = words[1];@@ -673,12 +746,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 +996,85 @@ } else if (subCmd == "reward") {- // "/event reward [range # | all | [player_name]] <#> item"- int rewardIndex = 3;- stackCount = 0;-- if (strspn(words[2].GetDataSafe(), "-0123456789") == words[2].Length())+ // "/event reward <range # | all | player_name | target> ['exp' value] ['item' count item] ['faction' faction value]+ // ['skill' <skill|'all'> [+-]value [max]] ['money' <circles|hexas|octas|trias> <value|'random'>]"+ size_t index = 3;+ 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)+ {+ 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)+ {+ 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++];+ if (words[index][0] == '+' || words[index][0] == '-')+ insert = true;+ value2 = words.GetInt(index++);+ 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 if (subCmd == "faction" && left >= 2)+ {+ name = words[index++];+ density = words.GetInt(index++);+ } else { subCmd = "help"; help = true;- return true; } }-- // last bit is the item name itself!- item = words.GetTail(rewardIndex); } else if (subCmd == "remove") {@@ -1397,6 +1506,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);@@ -6252,24 +6365,172 @@ 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;+ }+ + 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 // 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());++ text.Format("You have been awarded %d %s.", data.stackCount, data.itemName.GetDataSafe());+ psserver->SendSystemInfo(gmClientNum, text);++ 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")+ {+ for (int i=0; i<PSSKILL_COUNT; i++)+ {+ psSkillInfo* skill = CacheManager::GetSingleton().GetSkillByID(i);+ if (!skill) continue;+ modified |= ApplySkill(gmClientNum, target, skill, data.skillDelta, data.relativeSkill, data.skillCap);+ }+ }+ else+ {+ psSkillInfo* skill = CacheManager::GetSingleton().GetSkillByName(data.skillName);+ modified |= ApplySkill(gmClientNum, target, skill, data.skillDelta, data.relativeSkill, data.skillCap);+ }++ if (modified && target)+ {+ psserver->GetProgressionManager()->SendSkillList(target, false);+ }+ }++ if (data.moneyType) // award money+ {+ bool valid = true;+ 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)+ value = data.moneyCount;+ else+ value = psserver->rng->Get(INT_MAX-1)+1;+ psMoney money;+ money.Set(type, value);+ pchar->AdjustMoney(money, false);+ psserver->GetCharManager()->SendPlayerMoney(target);+ + 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);+ 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(); @@ -6307,7 +6568,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)@@ -6602,70 +6863,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) {@@ -6679,176 +6944,90 @@ 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)+{+ 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)+ return false;+ + psCharacter * pchar = target->GetCharacterData();+ + if (!pchar)+ return false;+ + if (relative && !value) {- psSkillInfo * skill = CacheManager::GetSingleton().GetSkillByName(data.skill);- if (skill == NULL)+ int base, current;+ if (skill->category == PSSKILLS_CATEGORY_STATS) {- 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);- }- }-- // 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")- {+ 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; } 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);+ int old_value = pchar->Skills().GetSkillRank(skill->id).Current();+ int new_value = value;+ int max = MAX_SKILL;+ + if (relative)+ new_value += old_value; - if (target->GetClient() && target->GetClient() != client)+ if (skill->category == PSSKILLS_CATEGORY_STATS)+ max = MAX_STAT;++ if (cap && cap < max)+ max = cap;++ if (new_value > max)+ new_value = max;+ else if (new_value < 0)+ new_value = 0;++ pchar->SetSkillRank(skill->id, new_value);+ 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) { // Inform the other player.- psserver->SendSystemOK(target->GetClientID(), "Your '%s' level was set to %d by a GM", data.skill.GetDataSafe(), data.value);+ 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)@@ -7699,7 +7878,7 @@ (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 == "reward") || (data.subCmd == "control" && data.gmeventName.Length() == 0) || (data.subCmd == "discard" && data.gmeventName.Length() == 0)) {@@ -7712,7 +7891,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"@@ -7766,12 +7947,20 @@ // reward player(s) if (data.subCmd == "reward") {- gmeventResult = gmeventManager->RewardPlayersInGMEvent(client,- data.rangeSpecifier,- data.range,- target,- data.stackCount,- data.item);+ 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; } @@ -8426,13 +8615,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 5627)+++ 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 5627)+++ 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 5627)+++ 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);Index: data/help.xml===================================================================--- data/help.xml (revision 5627)+++ data/help.xml (working copy)@@ -512,6 +512,9 @@ <topic name="/awardexp">/awardexp target value Awards progression points to a player for the completion of a GM run event. (enter a negative value to take away PP)</topic>+ <topic name="/award">/award [area:[players]:range|me|target|player|eid:EID|pid:PID] ['exp' value] ['item' count item] ['skill' [skill|'all'] [+-]value [max]] ['money' [circles|hexas|octas|trias] [value|'random']] ['faction' faction value]++Awards progression points, items, money, skills and factions to specified target(s)</topic> <topic name="/badtext">/badtext [first entry] [last entry] Shows what was told to the targeted npc and couldn't be understand by it.@@ -576,10 +579,8 @@ /event complete To reward the participants (all of them, those within a specified range or an individual - by name or by target) of a current event:-/event reward [range 0-100 | all | player] # [item name]-[item name] can be "exp" (experience) where # Progression Points are awarded.-[item name] can be "faction [faction name]" to adjust the faction standing.-NOTE: Exp is in PP not in experience, differently from awardexp and givekillexp+/event reward [range 0-100 | all | player | target] ['skill' [skill|'all'] [+-]value [max]] ['exp' value] ['item' count item] ['money' [circles|hexas|octas|trias] [value|'random']] ['faction' faction value]+NOTE: Exp is in PP not in experience If a GM wants to assume control of an ongoing event, because the original GM character has been deleted, or has abandoned it and is offline, the GM can enter: /event control [name]@@ -813,7 +814,7 @@ <topic name="/setquality">/setquality [target/eid/area/name] [quality] [max quality] Allows changing the quality of the targeted item. Max quality is optional.</topic>- <topic name="/setskill">/setskill [target] [skill|'all'] [value|-1]+ <topic name="/setskill">/setskill [target] [skill|'all'] [+-][value] [max] Set one of your or target's skills or stats to a specific value. Use 'all' as the name to set all skills and stats to the given value. Use -1 for value if you would like to view the current value of a skill or stat. If no value is given 100 will be used as default.</topic> <topic name="/setstackable">/setstackable [on|off|reset|info]