Game Development Community

Resource Exhaustion

by Dave Young · in RTS Starter Kit · 01/30/2006 (1:48 am) · 15 replies

Using World Domination Mod, I would like to be able to implement resource exhaustion, so that the trees can be destroyed as they are harvested, etc.

I see when I click on a resource, I briefly get a health bar. Could this somehow be used? The main problem as I see it as that the peons don't actually keep reference to the object they are resourcing.

It seems like they just have a destination and a resourceType, set when you click on the resource.
If I could get the resource object's id, I could schedule a decrement of health and then kill it when it reaches 0... I could do this at the same time the peon is scheduling their resource add. Checking, of course, for a positive amount, and then having them Idle of the resource is destroyed.

Whew! Ok, so any ideas on obtaining a reference to the resource object's ID?

#1
01/30/2006 (8:24 am)
I don't think it would be very hard to implement. I could use similarmyself but am trying to script in some other bits right now. If anyone had this implemented, I'd like to talk to you :D
#2
01/30/2006 (8:35 am)
I was able to hook the selection by adding some code to inputHandler.cs, and I can do a dump on the resource object to check it out. So I'm not at a roadblock anymore and will be actively working on this.
#3
01/30/2006 (10:58 am)
Good to hear!

Currently, there is no data stored on the resource sources themselves that would allow for this, but it isn't difficult, and could be done completely in script.

You would simply need to keep track of the "max resources available" via a script dynamic field, and then decrement it when it is harvested. You would then need to handle what you want to have happen when the resource is drained (remove/replace the shape with a different one, etc.), and then finally handle letting any peons that are currently harvesting from that resource that the resource isn't avail (not completely trivial, but not too difficult).
#4
01/30/2006 (11:32 am)
Stephen-

Here's how I am doing this so far, please give me your feedback. It seems to work, but I am concerned about it working for all clients (not sure about IDs sometimes).

Client Side:
In inputHandler.cs:
added a function:
function GuiRTSTSCtrl::onMouseDownResource(%this, %x, %y, %z, %type)
{
   %resHealthLeft = %type.getDataBlock().maxDamage - %type.getDamageLevel();
   echo("Resources Left in this object: " @ %resHealthLeft);
}


Server Side:

In resourceGeneration.cs:
Added a spawn value for resources like this:

datablock StaticShapeData(Gold){
    shapeFile = "~/data/shapes/rocks/rock1.dts";
    RTSUnitTypeName = "goldResource";
    category = "Resources";
    className = "Resource";
    maxDamage = 5000; //How much resource this item will hold. This lets it show up in the health HUD..cool!
};


In commands.cs:
Stored the id of the resource that was clicked on in the 'villager' variable currentTargetResource. I didn't declare it anywhere, just kind of made it up and set it:
function serverCmdIssueResourceMove(%client, %x, %y, %z, %type)
{
echo("serverCmdIssueResourceMove--looking for resource object (" @ %type @
      ") at" SPC %x SPC %y SPC %z );
 
   if (%client.selection.getObject(0).getTeam() != %client.getTeam())
      return;
   %destinationResource = %client.resolveObjectFromGhostIndex(%type);
echo("Resolved (" @ %type @ ") to server object (" @ %destinationResource @ ")");
      
   for (%i = 0; %i < ClientGroup.getCount(); %i++)
   {
      %cl = ClientGroup.getObject(%i);
      %cl.sendMoveEvent(%client.selection, %x SPC %y);
   }

   %center = "0 0 0";
   for (%i = 0; %i < %client.selection.getCount(); %i++)
   {
      %center = VectorAdd(%center, %client.selection.getObject(%i).getPosition());
   }
   %center = VectorScale(%center, 1.0 / %client.selection.getCount());

   for(%i = 0; %i < %client.selection.getCount(); %i++)
   {
      %obj = %client.selection.getObject(%i);
      //echo(%obj.getDataBlock().getName());

      if(%obj.getDataBlock().getName() !$= "villagerBlock") continue;
      if (!isObject(%destinationResource) )
      {
        echo("serverCmdIssueResourceMove--Failed resolving resource object, client thought (" @ %type @
             ") server thought it resolved to (" @ %destinationResource @ ")");
        return;
      }      
      %obj.resourceType = %destinationResource.resourceType;
      %obj.resourcePos = %destinationResource.getPosition();
      %obj.status = "Collecting";
      %obj.currentAmt = 0;
 //Store the ID of the resource object. not sure which works but one of them does!
      %obj.currentTargetResource = %destinationResource;
      %client.resolveObjectFromGhostIndex(%type).currentTargetResource = %destinationResource;
	  
echo("serverCmdIssueResourceMove-- (" @ %obj @ ") is moving to get resource (" @ 
     %obj.resourceType @ ") " @ %destinationResource @ " at (" @ %obj.resourcePos @ ")");
      %dest = %x SPC %y SPC %z;
      %offset = VectorSub(%obj.getPosition(), %center);
      %dest = VectorAdd(%dest, %offset);
      %obj.clearAim();

      %obj.setMoveGoal(%dest);
   }
}


And in avatars/player.cs, did a check on the current health of the resource object. If it has health left, allowed the harvesting; harvesting it also does damage. If no health left, destroy it.

function Player::collectResource(%this, %type ,%timeout)
{
// NOTE: The tracking of resource being carried (type and amount) isn't very authoritative.
// Currently, the player can "cheat" by setting a villager to collect an almost full carry amount
// on one resource, then manually change the villager to another resource, and in one gather cycle,
// fill up on the -new- resource and return. Best implementation (suggested) is to either allow the
// villager to track the amount for each possible resource type, and/or have their carryAmt set to 0
// if the currently harvesting resource type is not the same as currently carrying resource type (not implemented)

//This next line check the remaining health of the currentTargetResource
  %resHealthLeft = %this.currentTargetResource.getDataBlock().maxDamage - %this.currentTargetResource.getDamageLevel();
  if(%resHealthLeft > 5)
  {
  echo("Villager (" @ %this @ ") is collecting (" @ %this.resourceType @ ") from " @ %this.currentTargetResource @ " every (" @ %timeout/1000 @ ") seconds");
  %this.currentAmt +=5;
  %this.currentTargetResource.applyDamage(5);
  if(%this.currentAmt > %this.maxAmt)
  {
   echo("Villager (" @ %this @ ") is heading to Town Center carrying (" @ %this.resourceType @ ")");
   %TC = findTC(%this.client);  //this is the original findTC call, not the enhanced one
   echo("which is at (" @ %TC.getPosition() @ ")"); 
   if (%TC.getPosition() $= "")
   {
     echo("Player::collectResource--No TC Found! Idling");
     %this.status = "Idle";
     if(isEventPending(%this.resourceID) )
     {
       cancel(%this.resourceID);
     }
     return;
   }
   %this.TCLoc = %TC.getPosition();

   if(isEventPending(%this.resourceID))
   {
     cancel(%this.resourceID);
   }
   %this.status = "Full";

   %this.setMoveDestination(%this.TCLoc);
   %this.curGoal = %this.TCLoc;
 }
 else
 {
   %this.resourceID = %this.schedule (%timeout,"collectResource" , %type,  %timeout);
 }
 } // if resHealthLeft > 0
 else //kill the resource.  To add: send the villager to the TC to drop off if they harvested anything before depletion, also try to clear the harvesting event and the current resource ID.
 {
   
   %this.currentTargetResource.schedule($CorpseTimeoutValue - 1000, "startFade", 1000, 0, true);
   %this.currentTargetResource.schedule($CorpseTimeoutValue, "delete");
 }
}


This all seemed to do the trick, the villager mines the resource until its depleted, then it fades away. I have some more stuff to add of course.
1) Right now the current health of the resource object just gets echo'd. i will try to make it show up in the GUI
2) Not dump the selection so fast, so the selection circle will remain on it.
3) Figure out how to clear the 'harvesting' command from the villager
4) Maybe tell the villager to go to the nearest similar resource and start harvesting it
5) Play a death animation for the resource
6) Move the onDeath function to some datablock resources have in common. (Not necessary, but maybe useful somewhere else)

Do you see any problems with this implementation? I am mainly wondering what I did needlessly, and am just starting to wrap my head around ghosting.

Between this change and the enhanced findTC function I posted I might have the resource changes I am looking for in a RTS all wrapped up.
#5
01/30/2006 (1:09 pm)
I don't see any huge issues honestly, although I only skimmed your code. You'll of course want to test it out with multiple clients attached to a dedicated server for your most comprehensive test environment, or at a minimum test it out with a hosted multiplayer game and a connected client.
#6
01/30/2006 (6:10 pm)
Hey Dave, you're really catching on quick it looks like :)

I'm not much a scripter, I'm an artist and designer so I appreciate the code bit. My game is single player only so this should work for my uses.
#7
01/31/2006 (8:39 am)
Not to go off topic to much but I remember another person who caught on very quickly to the RTS kit when it was first released. He made several nice additions and resources to it and seemed to know it inside and out... we knew him as Stephen Zepp, now he's Employee Stephen Zepp. ;)
#8
01/31/2006 (8:56 am)
Thanks Chip! And his point is a very, very good one. My transition from Torque newbie, to RTS-SK expert, to Associate, to Employee was based very much (I'd say probably 70%+) on the fact that I participated in the community via the forums...and that path is still the most direct way to gain the attention of GG in a professional light.

More than 50% of our employees came from the community, and that ratio is actually still going up...and we're always on the lookout!
#9
01/31/2006 (10:07 am)
Thanks for the encouragement. I'm enjoying the learning process! Feels like there's a light at the end of the tunnel. While I am a developer for a living, there's something more enjoyable about getting little animated units walking around with a purpose that satisfies some deep urging hehe.
#10
01/31/2006 (12:30 pm)
You know Stephen, here lately it seems you're the only GG employee posting frequently..... did you lock the rest of them up and take the office for your own?

(j/k I know they are all very busy... hopefully someone is cranking out the update to the RTS kit ;))
#11
01/31/2006 (1:22 pm)
Actually, part of my job is to be the GarageGames "front line troop" when it comes to the forums. Many of the developers do focus on their own specific forum areas, but myself and Jeff Tunnell are the only ones that read every message posted (and even then, we still miss some!).

When I find a post that could even slightly be interesting to someone, I email off a link to them so they can focus on development!
#12
01/31/2006 (1:31 pm)
@Dave
Keep up the good work man. Maybe you can give us some more great resources for this kit. We need tons and tons and tons!!! And some TDN entries :) I'd move this over to the Resources forum so nobody will miss it.

@Stephen
I figured you were kinda being a community liasion. Also I hope nobody at GG may have took that comment out of context in some form. I absolutely meant nothing by it :)
#13
01/31/2006 (1:31 pm)
I have implemented this into my game today, would've gotten to it sooner but was scripting some other things and then converting my project files to VC++ 2005. Seems to work as you want, though I haven't tested it online and probably won't be, as I stated earlier, my game is single player.

The villagers collecting resources seems to work. The exploit you mentioned doesn't seem to occur. I tested seeing a villager go from some stones and collect as much as it could, then sending it to some trees. It only came back with the trees. I also tried sending to the stones, and then back to the stones afterwards. It only brought back one set.

Dave, if you wanted to collaborate on adding things to the RTS pack, let me know. I have a design doc and I am an artist, not the best scripter however.
#14
01/24/2010 (4:17 pm)
Works great with TGE 152 + RTS Kit + World Dom mod -- only thing is the mouse select function never gets called. But when I click on a resource, it shows its health bar - which is good enough.

Anyone else get this working in 1.5.2?
#15
02/21/2010 (7:24 am)
Its missing (1) thing ... inputHandler.cs, the check for Resource on mouse down
function GuiRTSTSCtrl::onMouseDown(%this, %obj, %x, %y, %z)
{
   echo("GuiRTSTSCtrl::onMouseDown" @ %obj.getClassName() @ " : " @ %obj.getId());
   
   switch$(%obj.getClassName())
   {
      case "RTSUnit":
         %this.onMouseDownUnit(%obj);
      case "TerrainBlock":
         %this.onMouseDownTerrain(%x,%y,%z);
      case "RTSBuilding":
         %this.onMouseDownBuilding(%obj);
      case "Resource":
         %this.onMouseDownResource(%x,%y,%z,%obj);
      default:
         echo("GuiRTSTSCtrl::onMouseDown - invalid object selected (" @ %obj.getClassName() @ ")");
         return;         
   }
}