Game Development Community

Peons to build buildings

by Ed Johnson · in RTS Starter Kit · 03/08/2005 (9:36 am) · 21 replies

Has anyone implemented a way to let peons know they're needed to construct a building
(or repair a building, etc).

The 'World Domination' mod stated that was left out to be project specific, but I'm sure someones thrown together something simple.
I was looking through rtsEvents.cs and commands.cs trying to get an idea how the peons take commands.

Thanks!
Page «Previous 1 2
#1
03/08/2005 (4:27 pm)
Actually, you can mimic the way peons harvest in the "World Domination" mod to have them also "work on" buildings. Just have them do the following:

(Note: The mod does require you to have a peon selected to get the building selection menu, so you already have a peon "ready for work"):

1) Assign them a move to location (the building placement point).
2) Assign them a "next task" variable, such as: %selectedPeon.nextTask = "PlaceBuilding"
3) Set the information that the building placement requires as peon variables as well:
%peon.taskTransform = $NewBuilding.getTransform();
%peon.taskObjectData = $NewBuilding.theDataBlock();
4) In onReachDestination(), have it check for the .nextTask, and if it is "PlaceBuilding", then either send the commandToServer('PlaceBuilding',...) command right after it reaches the desired spot, or even schedule that command at a certain interval later to simulate time to construct the building.
#2
03/08/2005 (5:51 pm)
Hmmm.... could you point me to the relevent files with the harvest function?

I've read through:
./client/scripts/rtsEvents.cs - seems to be the popup notifications when somethings done
./client/scripts/buildings.cs - data for buildings, and function to place them
./client/scripts/stats.cs - some character attributes?
./server/scripts/core/commands.cs - server commands.. like 'serverCmdIssueResourceMove'
./server/scripts/resources/resoirces-server.cs - handles the resources, but not the gathering thereof
./server/scripts/items/buildings.cs - server buildings stuff & commands 'serverCmdPlaceBuilding'

Thanks!
#3
03/08/2005 (6:25 pm)
Those are all in the server side player.cs. All of the harvesting stuff is part of the World Domination mod, except for the base move to destination functionality, which is part of the stock RTS-SK (and also in the same file).
#4
03/08/2005 (7:21 pm)
I found onReachDestination, so I know what to do there, I'm having a little difficulty finding the best way to do the first 3 parts.

Would this be setup when I press the build buttons, so the Peon selected is sent off to build it, if so I just need to find
the function called when the button is pressed, and tell it to have the peon selected moveTo() there, as you said.

I understand the logic of what your talking about, I just dont know which one of the dozens of files to do this in.
#5
03/08/2005 (7:37 pm)
Ok, little more structure for you!
NOTE: This explanation is based on having the World Domination mod already installed and working properly.
SECOND NOTE: The first two RTS-SK installers had a minor missing functionality that is described here. Rumor has it that the latest installer has this, or very similar functionality, so if the following code doesn't work for you, then add in what is described in that thread.

When the player clicks on a peon, and then clicks on a building to place, the peon is still selected (we'll get back to this in a bit). The player moves the RTSBuildingMarker around, and then left-clicks to place the building.

At that time, the code (C++) calls the script in client/scripts/buildings.cs: function GuiRTSTSCtrl::placeBuilding(%this). This is our entry point.

This function then sends a command to the server with the information about the RTSBuildingMarker's transform, datablock, etc. On the server, we have the function /server/scripts/items/building.cs: function serverCmdPlaceBuilding(%conn, %store, %transform, %data, %zTweak). This is where we want to start.

function serverCmdPlaceBuilding(%conn, %store, %transform, %data, %zTweak)
{

  if (%conn.selection.getCount() != 1)
  {
    // right now we can only use one peon to do stuff
    messageClient(%conn, 'MsgPurchaseDenied', "", "Can only have one peon selected, and you don't! Talk to the devs, this shouldn't happen." );
    return;
  }
  %activePeon =   %conn.selection.getObject(0);
  if (%activePeon.getRTSUnitTypeName() !$= "villager")
  {  // NOTE: this needs to be expanded, different entities will have different datablocks for their peons.
    messageClient(%conn, 'MsgPurchaseDenied', "", "Thats not a peon! Talk to the devs, this shouldn't happen." );
    return;
  }
  // set up this peon to do the work
  %activePeon.status = "MoveToBuild";
  %activePeon.buildTime = 20000; // 20 seconds per work effort for now, this can be adjusted based on lots of things
                                   // like underlying terrain type, peon level, etc.
  %activePeon.clearAim();

     %buildWorkSpot = getWords(%transform, 0, 2);
    echo("serverCmdPlaceBuilding()--our initial build location is (" @
      %buildWorkSpot @ ")");
    // make sure client can pay for the building

    if (%store $= "LOCAL")
    {
      %activeStore = %conn.resourceStore;
    }
    else
    {
      %activeStore = %store;
    }
   
    %requiredSupplies = $Buildings::requiredBuildSupplies[(getBuildingIndexFromDataBlockName( %data )),0];
    %requestId = $Buildings::requestId[(getBuildingIndexFromDataBlockName( %data )),0];
   
    %authString = resourceStore::requestSpendSupplies(%conn,
                                                      %activeStore,
                                                      %requestId, 
                                                      %requiredSupplies, 
                                                      "false");

    %successStatus = getWord(%authString,0);
    if (%successStatus $= "DENY") 
    {
      messageClient(%conn, 'MsgPurchaseDenied', "", "Cannot place Building! missing:" SPC getWords(%authString, 2) );
    	return;
    }
    else
    {
//  	echo("serverCmdPlaceBuilding--request by" SPC %client SPC getWord(%authString, 1) SPC "APPROVED");
    }

    echo("serverCmdPlacingBuilding()--storing values for later use");
    %activePeon.nextJobType = "Build";
    %activePeon.nextJobData = %data;
    %activePeon.nextJobTransform = %transform;
    %activePeon.setMoveGoal(%buildWorkSpot);  
}

(NOTE: fixed typo/added in function header--thanks for the correction!
#6
03/08/2005 (7:42 pm)
Next, we want to add the following function in /server/scripts/player.cs:

function Player::constructBuilding(%this)
{

  %data = %this.nextJobData;
  %transform = %this.nextJobTransform;
  %conn = %this.client;
  echo("Player::constructBuilding(): %data is (" @ %data @ "), transform is (" @ 
%transform @  ")");
    
   // change the building's placement transform to factor in the terrain adjustment
   %b = new RTSBuilding()
   {
      datablock = %data;
      scale = $Buildings::ShapeScale[(getBuildingIndexFromDataBlockName( %data ))];
   };

   %transformFirstHalf = getWords(%transform, 0, 1);
   %transformSecondHalf = getWords(%transform, 3);
   %transformHeight = getWord(%transform, 2);
   %buildingBox = %b.getObjectBox();
   %buildingBoxZLen = getWord(%buildingBox, 5) - getWord(%buildingBox, 2);
   %buildingBoxZPos = %transformHeight + %buildingBoxZLen/2;
   %newBuildingTransform = %transformFirstHalf SPC %buildingBoxZPos SPC %transformSecondHalf;
echo("Original Transform: (" @ %transform @ "), transform Height: (" @
%transformHeight @ ") bounding box: (" @ %buildingBox @ "), new transform (" @ %newBuildingTransform @ ")");

   %b.setTransform( %newBuildingTransform );

   
   %b.client = %conn;
   %b.setTeam(%conn.getTeam());
   %b.setControllingConnection(%conn);
   %b.level = 0;
   %conn.buildings.add(%b);

   
   %b.setActionThread("idle");
  %b.initBuildingActions();
  
  %this.nextJobData = "";
  %this.nextJobTransform = "";
  %this.status = "Idle";
  %this.curGoal = "";
  
  
}

NOTE: This will place the building directly on top of the peon--you probably want to modify the build moveto spot in the middle post to be offset from the center of the building. You would want to determine the bounding box's larger x or y axis, and maybe put the peon at 1/2 + 5 or so to be in a better spot.
#7
03/08/2005 (7:48 pm)
Now, in the same file, you want to add the following code at the top of the function:

if (%this.status $= "MoveToBuild" && %this.curGoal $= "")
   {
     %this.status = "Building";
     %this.buildScheduleID = %this.schedule(%this.buildTime,"constructBuilding");
   }

DISCLAIMER!!: This is code that I ripped out of our own project and modified to demonstrate the idea of what you are looking for. It has not been tested, or even byte code compiled, so please don't expect it to work out of the box! There will probably be a typo or two, or some variables named wrong. Play with it, see if you can get it to work, and if you have any problems let me know (console reports would help a lot!).
#8
03/08/2005 (8:09 pm)
Wowzers, thanks alot! I'll try this out tonight!

Edit: This is an error I got last night:
[b]Console Output[/b]
Loading compiled script starter.RTS/server/scripts/items/staticShape.cs.
Compiling starter.RTS/server/scripts/items/building.cs...
starter.RTS/server/scripts/items/building.cs Line: 209 - Syntax error.
>>> Advanced script error report.  Line 417.
>>> Some error context, with ## on sides of error halt:
    // right now we can only use one peon to do stuff

    messageClient(%conn, '##M##sgPurchaseDenied', "", "Can only have one peon selected, and you don't! Talk to the devs, this shouldn't happen." );
>>> Error report complete.

Thought it had to do with MsgPurchaseDenied, after some tweaking, I had to remove the last curly bracket ( } )
from the serverCmdPlaceBuilding code you sent. Then it ran good, until I try to place a building. When I click where to place it, none of the peons walk there (yet)

It seems to be faulting at:
if (%activePeon.[b]getRTSUnitTypeName()[/b] !$= "villager")

Which makes sense because it doesnt exist. Not until I read this post. Many Thanks Stephen!
#9
03/09/2005 (6:30 pm)
Cool, after searching the forums for getRTSUnitTypeName I found your thread. Followed it and now it works as expected.

Next up...
[] using an offset so the building doesnt appear on top of the villager ;-)
[] animate the construction, in at least 3 steps (rubble, half done, done)
#10
03/09/2005 (6:45 pm)
Thanks for the correction, and I added it as well as your note about getRTSUnitTypeName to the posts. Glad it worked out for you, and I'd love to see how you handle the offset, if you wouldn't mind posting it once you get it working!

About your last functionality, I actually did a basic "under construction"/"finally finished" mod to our project--it shouldn't be too difficult, just look at how the schedule command is used in the above example!
#11
03/09/2005 (7:28 pm)
Yeah when I do figure it out it will definitly get posted back here in the forums. Its the least I could do :-)

Because I like to pseudo-code things out before actually coding, heres my thoughts about the offset..

[] find buildings' larger X or Y axis / 2 (radius = $offsetnum )
[] make peon move to the outer edge of the building ( $dest - $offsetnum )

img189.exs.cx/img189/5241/bounds9oi.png
#12
03/09/2005 (8:06 pm)
That does sound like a good plan!
#13
10/21/2006 (7:26 am)
There is no /server/scripts/player.cs file. There are three folders, each with its own player.cs file in it. Looking over each one, I determined the correct one to modify to be /server/scripts/fx/player.cs since it has all the related code.

After following all the instructions above, I deleted all the .dso files and ran the thing, but when I selected a peon and tried to place a building I got an error message like "Thats not a peon! Contact the developers, since this shouldn't happen."

Any ideas?
#14
10/21/2006 (2:04 pm)
You could try reading through this forum thread a bit more in depth, and more importantly the link that is provided above, which explains at least one of the possible issues you are having.

In addition, as was also mentioned in this thread, the example code was drawn from my personal project at the time, not the stock RTS-SK, which suggests why the path is different for you.
#15
10/21/2006 (5:52 pm)
Quote:
if (%activePeon.getRTSUnitTypeName() !$= "villager")
{ // NOTE: this needs to be expanded, different entities will have different datablocks for their peons.
messageClient(%conn, 'MsgPurchaseDenied', "", "Thats not a peon! Talk to the devs, this shouldn't happen." );
OK, I'll ignore your warning message and listen to the opposite thing you say now. ;) Don't talk to the devs, just look it up yourself. Oh the tragedy that is my life. I have to actually use my brain and spend several minutes reading through a post, to solve the problem on my own. Oh well. ;)

Quote:
Stephen Zepp
Employee Posted: Mar 09, 2005 21:53
Based on the forum-mod changed title to this original post, I can assume that very similar functionality was implemented in the latest release, so if you are looking to add this functionality, you may want to search for the new implementation instead. I'm looking now, and if I can find it I'll post the new function name here!

Did you ever find it? Is there a newer better way to do things?

If not I'll just copy and paste over what you post there, in the files I'm suppose to edit, and hopefully it'll all work out fine then.
#16
04/29/2007 (3:08 pm)
WD works perfect for me. Then I passed to work on this resource and everything seems to be fine, but in the last moment: the building doesnt build!

All looks fine:

the menu of the villager works fine
the correspondient resources of the building are taken when i click the ground
the peon actually go to the place (I fix the RTSUnitTypeName issue)

but the building doesnt appear.

I think maybe was an issue with the construction time, so i changed it, but makes no difference.

Any ideas where i can continue looking?
#17
05/02/2007 (4:42 pm)
Ok, its done. I actually put this

if (%this.status $= "MoveToBuild" && %this.curGoal $= "")
   {
     %this.status = "Building";
     %this.buildScheduleID = %this.schedule(%this.buildTime,"constructBuilding");
   }

at the bottom of serverCmdPlaceBuilding instead of in the top of constructBuilding (after replacing each %this with %activePeon )

Advise: in this manner the building will appear AFTER the building time has passed


Edit: Actually, I think I misunderstood Stephen, that block (I believe now) goes at the top of Player::onReachDestination in player.cs, without further modification.
#18
02/08/2009 (1:35 pm)
I realize this thread is old and, as Novack pointed out a few days ago, I'm not on the current codebase. I thought I'd post my (less than elegant) solution for not having your "peon" end up in the center of the building. Just replace this function in player.cs.
function Player::setMoveGoal(%this, %dest)
{
   // Dan ADDED: Special movement for MoveToBuild so the commoner doesn't 
   //            end up in the center of the building.
   if (%this.status $= "MoveToBuild")
   {
      if (getWord(%dest,0) > getWord(%this.getPosition(),0))
         %dest = getWord(%dest, 0)-5 SPC getWord(%dest,1);   
      else
         %dest = getWord(%dest,0)+5 SPC getWord(%dest,1);
   }
   %this.curGoal = %dest;
   
   // Kick off the movement.
   %this.onReachDestination(%this.getPosition());
}

I don't know if this actually helps anyone. Especially since the thread is so old. I thought I'd throw it out there either way. Thanks to Stephen for this!
#19
01/24/2010 (12:53 am)
Might be tricky to get this working with TGE 1.5.2 build ... when I left click to build a Building - my unit it auto unselected. So the code errors out, but maybe its something I did.
#20
10/25/2012 (6:00 pm)
jeff did you ever find a way to get peons to move to were you were building the buildings?
Page «Previous 1 2