rendered paste bodyIndex: 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). exp, money and faction values are relative to the current ones, the skill value is relative to the current one if proceeded with + or - (in that case it's recommended to specify the max skill level to not allow players to reach levels that shouldn't be reachable).</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,9 +814,9 @@ <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>+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 +0 for value if you would like to view the current value of a skill or stat. If you use relative assignment (e.g. +5 or -10 as value) it's recommended to specify max accordingly to not adjust the level of a player over the trainable one.</topic> <topic name="/setstackable">/setstackable [on|off|reset|info] Enables or disables the ability to stack the targeted item. Info will give the current status of this flag. Reset returns the item to the default stack mode for the item.</topic>Index: 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,87 @@ } 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);+ + subCmd = "reward"; } else if (subCmd == "remove") {@@ -1397,6 +1508,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);@@ -4104,42 +4219,13 @@ void AdminManager::CreateMoney(MsgEntry* me, psAdminCmdMessage& msg, AdminCmdData& data,Client *client) {- bool valid = true;- Money_Slots type;-- 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(INT_MAX-1)+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);-+ psRewardData rewardData;+ rewardData.moneyType = data.item;+ rewardData.moneyCount = data.value;+ if (data.random)+ rewardData.moneyCount = 0;+ + AwardToTarget(client->GetClientNum(), client, rewardData); } void AdminManager::RunScript(MsgEntry *me, psAdminCmdMessage& msg, AdminCmdData& data,Client *client, gemObject* object)@@ -6252,24 +6338,185 @@ 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(target->GetClientNum(), text);++ if (gmClientNum != target->GetClientNum())+ {+ 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);+ + csString text;+ text.Format("You have been awarded %d %s.", value, data.moneyType.GetDataSafe());+ psserver->SendSystemInfo(target->GetClientNum(), text);++ if (gmClientNum != target->GetClientNum())+ {+ 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);+ 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 +6554,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 +6849,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 +6930,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 +7864,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)) {@@ -7712,7 +7876,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 +7932,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 +8600,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);