All pastes #1838004 Raw Copy code Copy link Edit

clueless

public text v1 · immutable
#1838004 ·published 2010-03-13 22:00 UTC
rendered paste body
Index: 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);