2025-07-22 01:18 CEST

View Issue Details Jump to Notes ]
IDProjectCategoryView StatusLast Update
0001123Spring engineGeneralpublic2008-10-13 12:43
Reporterel_matarife 
Assigned ToKloot 
PrioritynormalSeverityblockReproducibilityalways
StatusresolvedResolutionfixed 
Product Version0.77b3 
Target VersionFixed in Version 
Summary0001123: Player bonus / handicap exploit
DescriptionHandicap applies to ALL incoming metal / energy including reclaim, so you can build units / structures and reclaim for more than you spent, leading to an infinite economy exploit. Attached is a replay proving it.
TagsNo tags attached.
Checked infolog.txt for Errors
Attached Files
  • ? file icon 20081012_121814_SpeedMetal_0.77b3.sdf (73,854 bytes) 2008-10-12 19:26
  • diff file icon handicapreclaim.diff (5,245 bytes) 2008-10-12 20:05 -
    Index: rts/Game/Team.cpp
    ===================================================================
    --- rts/Game/Team.cpp	(revision 6664)
    +++ rts/Game/Team.cpp	(working copy)
    @@ -195,9 +195,9 @@
     }
     
     
    -void CTeam::AddMetal(float amount)
    +void CTeam::AddMetal(float amount, bool handicap)
     {
    -	amount *= handicap;
    +	if (handicap) {	amount *= handicap; }
     	metal += amount;
     	metalIncome += amount;
     	if (metal > metalStorage) {
    @@ -207,9 +207,9 @@
     }
     
     
    -void CTeam::AddEnergy(float amount)
    +void CTeam::AddEnergy(float amount, bool handicap)
     {
    -	amount *= handicap;
    +	if (handicap) {	amount *= handicap; }
     	energy += amount;
     	energyIncome += amount;
     	if (energy > energyStorage) {
    Index: rts/Game/Team.h
    ===================================================================
    --- rts/Game/Team.h	(revision 6664)
    +++ rts/Game/Team.h	(working copy)
    @@ -21,8 +21,8 @@
     	void SlowUpdate();
     
     
    -	void AddMetal(float amount);
    -	void AddEnergy(float amount);
    +	void AddMetal(float amount, bool handicap = true);
    +	void AddEnergy(float amount, bool handicap = true);
     	bool UseEnergy(float amount);
     	bool UseMetal(float amount);
     	bool UseEnergyUpkeep(float amount);
    Index: rts/Sim/Features/Feature.cpp
    ===================================================================
    --- rts/Sim/Features/Feature.cpp	(revision 6664)
    +++ rts/Sim/Features/Feature.cpp	(working copy)
    @@ -325,13 +325,13 @@
     
     		if ((modInfo.reclaimMethod == 1) && (reclaimLeft == 0)) {
     			// All-at-end method
    -			builder->AddMetal(def->metal);
    -			builder->AddEnergy(def->energy);
    +			builder->AddMetal(def->metal, false);
    +			builder->AddEnergy(def->energy, false);
     		}
     		else if (modInfo.reclaimMethod == 0) {
     			// Gradual reclaim
    -			builder->AddMetal(metalFraction);
    -			builder->AddEnergy(energyFraction);
    +			builder->AddMetal(metalFraction, false);
    +			builder->AddEnergy(energyFraction, false);
     		}
     		else {
     			// Chunky reclaiming, work out how many chunk boundaries we crossed
    @@ -340,8 +340,8 @@
     			const int newChunk = ChunkNumber(reclaimLeft);
     			if (oldChunk != newChunk) {
     				const float noChunks = (float)oldChunk - (float)newChunk;
    -				builder->AddMetal(noChunks * def->metal * chunkSize);
    -				builder->AddEnergy(noChunks * def->energy * chunkSize);
    +				builder->AddMetal(noChunks * def->metal * chunkSize, false);
    +				builder->AddEnergy(noChunks * def->energy * chunkSize, false);
     			}
     		}
     
    Index: rts/Sim/Units/Unit.cpp
    ===================================================================
    --- rts/Sim/Units/Unit.cpp	(revision 6664)
    +++ rts/Sim/Units/Unit.cpp	(working copy)
    @@ -729,7 +729,7 @@
     			const float buildDecay = 1.0f / (buildTime * modInfo.constructionDecaySpeed);
     			health -= maxHealth * buildDecay;
     			buildProgress -= buildDecay;
    -			AddMetal(metalCost * buildDecay);
    +			AddMetal(metalCost * buildDecay, false);
     			if (health < 0.0f) {
     				KillUnit(false, true, NULL);
     			}
    @@ -1750,7 +1750,7 @@
     
     		health += maxHealth * part;
     		if (beingBuilt) {
    -			builder->AddMetal(-metalUse * modInfo.reclaimUnitEfficiency);
    +			builder->AddMetal(-metalUse * modInfo.reclaimUnitEfficiency, false);
     			buildProgress+=part;
     			if(buildProgress<0 || health<0){
     				KillUnit(false, true, NULL);
    @@ -1761,7 +1761,7 @@
     
     		else {
     			if (health < 0) {
    -				builder->AddMetal(metalCost * modInfo.reclaimUnitEfficiency);
    +				builder->AddMetal(metalCost * modInfo.reclaimUnitEfficiency, false);
     				KillUnit(false, true, NULL);
     				return false;
     			}
    @@ -1961,14 +1961,14 @@
     }
     
     
    -void CUnit::AddMetal(float metal)
    +void CUnit::AddMetal(float metal, bool handicap)
     {
     	if (metal < 0) {
     		UseMetal(-metal);
     		return;
     	}
     	metalMakeI += metal;
    -	gs->Team(team)->AddMetal(metal);
    +	gs->Team(team)->AddMetal(metal, handicap);
     }
     
     
    @@ -1986,14 +1986,14 @@
     }
     
     
    -void CUnit::AddEnergy(float energy)
    +void CUnit::AddEnergy(float energy, bool handicap)
     {
     	if (energy < 0) {
     		UseEnergy(-energy);
     		return;
     	}
     	energyMakeI += energy;
    -	gs->Team(team)->AddEnergy(energy);
    +	gs->Team(team)->AddEnergy(energy, handicap);
     }
     
     
    Index: rts/Sim/Units/Unit.h
    ===================================================================
    --- rts/Sim/Units/Unit.h	(revision 6664)
    +++ rts/Sim/Units/Unit.h	(working copy)
    @@ -118,9 +118,9 @@
     
     	bool AllowedReclaim(CUnit *builder);
     	bool UseMetal(float metal);
    -	void AddMetal(float metal);
    +	void AddMetal(float metal, bool handicap = true);
     	bool UseEnergy(float energy);
    -	void AddEnergy(float energy);
    +	void AddEnergy(float energy, bool handicap = true);
     	void PushWind(float x, float z, float strength);		//push the new wind to the script
     	void SetMetalStorage(float newStorage);
     	void SetEnergyStorage(float newStorage);
    Index: rts/Sim/Units/UnitTypes/Factory.cpp
    ===================================================================
    --- rts/Sim/Units/UnitTypes/Factory.cpp	(revision 6664)
    +++ rts/Sim/Units/UnitTypes/Factory.cpp	(working copy)
    @@ -271,7 +271,7 @@
     	cob->Call("StopBuilding");
     	if (curBuild) {
     		if (curBuild->beingBuilt) {
    -			AddMetal(curBuild->metalCost * curBuild->buildProgress);
    +			AddMetal(curBuild->metalCost * curBuild->buildProgress, false);
     			curBuild->KillUnit(false, true, NULL);
     		}
     		DeleteDeathDependence(curBuild);
    
    diff file icon handicapreclaim.diff (5,245 bytes) 2008-10-12 20:05 +

-Relationships
+Relationships

-Notes

~0002823

el_matarife (reporter)

Lurker wrote a fix, and hooked me up with the diff since he couldn't attach it to this or upload it to SVN.

~0002825

imbaczek (reporter)

committed in r6686, please test and report if it's fixed.

~0002827

Kloot (developer)

Last edited: 2008-10-12 22:18

On a general note, this ...

if (handicap) { amount *= handicap; }

... is not a very useful expression since handicap is a bool, ie. if it is true then <amount> is just multiplied by 1 (no-op) and if it is false then <amount> is left untouched. That means the patch won't work.



float f(float amount, bool arg) {
    if (arg) { amount *= arg; }
    return amount;
}

int main(void) {
    printf("%f\n", f(5.0f, 0)); // 5.0
    printf("%f\n", f(5.0f, 1)); // 5.0
    printf("%f\n", f(5.0f, 2)); // 5.0
    printf("%f\n", f(5.0f, 3)); // 5.0
    return 0;
}



Also, the patch breaks handicap itself (a value of 100 which should double your commander's metal income gives only the default amount).

~0002828

imbaczek (reporter)

i admit i didn't do a thorough review, and lurker can't even see this mantis issue since it's marked private, so he won't see any comments ^_^

~0002829

imbaczek (reporter)

aye i'm not thinking too well today, only just understood what you were talking about... will fix asap.

~0002830

el_matarife (reporter)

Well, I've been thinking about it and I guess we can open this up. It's easy enough to work around this for now, and since we know it will be fixed soon there's no reason to keep it private.

~0002831

imbaczek (reporter)

fixed the fix.

also opening up to public disclosure at reporter's request.

~0002832

lurker (reporter)

I told matarife I hadn't been able to test it, I guess he neglected to put that in the mantis comment..

~0002839

Kloot (developer)

fixed now
+Notes

-Issue History
Date Modified Username Field Change
2008-10-12 19:25 el_matarife New Issue
2008-10-12 19:26 el_matarife File Added: 20081012_121814_SpeedMetal_0.77b3.sdf
2008-10-12 20:05 el_matarife File Added: handicapreclaim.diff
2008-10-12 20:06 el_matarife Note Added: 0002823
2008-10-12 21:44 imbaczek Note Added: 0002825
2008-10-12 21:50 Kloot Status new => confirmed
2008-10-12 22:04 Kloot Note Added: 0002827
2008-10-12 22:06 Kloot Note Edited: 0002827
2008-10-12 22:06 imbaczek Note Added: 0002828
2008-10-12 22:18 Kloot Note Edited: 0002827
2008-10-12 22:32 imbaczek Note Added: 0002829
2008-10-12 22:44 el_matarife Note Added: 0002830
2008-10-12 22:52 imbaczek Note Added: 0002831
2008-10-12 22:52 imbaczek View Status private => public
2008-10-13 02:47 lurker Note Added: 0002832
2008-10-13 12:43 Kloot Status confirmed => resolved
2008-10-13 12:43 Kloot Resolution open => fixed
2008-10-13 12:43 Kloot Assigned To => Kloot
2008-10-13 12:43 Kloot Note Added: 0002839
+Issue History