Index: src/server/adminmanager.cpp===================================================================--- src/server/adminmanager.cpp (revision 5627)+++ src/server/adminmanager.cpp (working copy)@@ -673,12 +673,14 @@ } else {+ if(words[3][0] == '+' || words[3][0] == '-')+ insert = true; value = words.GetInt(3); } } else {- value = -2;+ help = true; } return true; }@@ -6650,9 +6652,9 @@ } } // Not a copy, just proceed as normal- else if (data.skill.IsEmpty() || data.value == -2)+ else if (data.skill.IsEmpty() || data.help) {- psserver->SendSystemError(me->clientnum, "Syntax: /setskill [target] [skill|'all'] [value|-1] | [target] copy [source]");+ psserver->SendSystemError(me->clientnum, "Syntax: /setskill [target] [skill|'all'] [+-][value] | [target] copy [source]"); return; }@@ -6679,15 +6681,16 @@ 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);+ // use signed int as we're accepting relative values+ int value = data.value;+ // use the minimum here to not award values bigger than possible by setting single skill+ int max = MIN(MAX_SKILL, MAX_STAT); if (data.skill == "all") { // if the value is out of range, send an error- if (data.value != -1 && (value < 0 || value > max))+ if (!data.insert && (value < 0 || value > max) || data.insert && (value < -max || value > max)) {- psserver->SendSystemError(me->clientnum, "Valid values are between 0 and %u", max);+ psserver->SendSystemError(me->clientnum, "Valid values are between 0 and %d", max); return; }@@ -6696,9 +6699,7 @@ psSkillInfo * skill = CacheManager::GetSingleton().GetSkillByID(i); if (skill == NULL) continue;- unsigned int old_value = pchar->Skills().GetSkillRank(skill->id).Current();-- if(data.value == -1)+ if(data.insert && data.value == 0) { PSITEMSTATS_STAT stat = skillToStat(skill->id); if (stat != PSITEMSTATS_STAT_NONE)@@ -6707,32 +6708,49 @@ 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);+ psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %d", 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);+ psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %d (%d)", 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);+ psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %d", 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);+ psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %d (%d)", 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);+ int old_value = pchar->Skills().GetSkillRank(skill->id).Current();+ int new_value;+ if (data.insert)+ {+ if (value > 0)+ new_value = old_value + value > max ? max : old_value + value;+ else+ new_value = old_value + value < 0 ? 0 : old_value + value;+ }+ else+ {+ new_value = value;+ }++ pchar->SetSkillRank(skill->id, new_value);+ psserver->SendSystemInfo(me->clientnum, "Changed '%s' of '%s' from %d to %d", skill->name.GetDataSafe(), target->GetName(), old_value, new_value); } }+ + if (data.insert && data.value == 0)+ return;- 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);+ if (data.insert)+ psserver->SendSystemOK(target->GetClientID(), "All your skills were adjusted by %d by a GM", value);+ else+ psserver->SendSystemOK(target->GetClientID(), "All your skills were set to %d by a GM", value); } } else if (data.skill == "copy")@@ -6764,8 +6782,7 @@ return; }- unsigned int old_value = pchar->Skills().GetSkillRank(skill->id).Current();- if (data.value == -1)+ if (data.insert && data.value == 0) { PSITEMSTATS_STAT stat = skillToStat(skill->id); if (stat != PSITEMSTATS_STAT_NONE)@@ -6774,37 +6791,44 @@ 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);+ psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %d", 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);+ psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %d (%d)", 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);+ psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %d", 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);+ psserver->SendSystemInfo(me->clientnum, "Current '%s' of '%s' is %d (%d)", skill->name.GetDataSafe(), target->GetName(), base, current); } return; }- else if (skill->category == PSSKILLS_CATEGORY_STATS && (value < 0 || value > MAX_STAT))- {- psserver->SendSystemError(me->clientnum, "Stat values are between 0 and %u", MAX_STAT);- return;- }- 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);+ int old_value = pchar->Skills().GetSkillRank(skill->id).Current();+ int new_value;+ if (data.insert)+ new_value = old_value + value;+ else+ new_value = value;+ if (skill->category == PSSKILLS_CATEGORY_STATS)+ max = MAX_STAT;+ else if (skill->category != PSSKILLS_CATEGORY_STATS)+ max = MAX_SKILL;++ if (new_value > max)+ new_value = max;+ else if (new_value < 0)+ new_value = 0;++ pchar->SetSkillRank(skill->id, new_value);+ psserver->SendSystemInfo(me->clientnum, "Changed '%s' of '%s' from %d to %d", 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(), data.value);+ psserver->SendSystemOK(target->GetClientID(), "Your '%s' level was set to %d by a GM", data.skill.GetDataSafe(), new_value); } }