Author Topic: New Stuff  (Read 931 times)

Offline Eddy-B

  • Hero Member
  • *****
  • Posts: 1194
    • http://www.eddy-b.com
New Stuff
« on: August 13, 2005, 02:17:02 PM »
Handy routines that should be in everyone's source/header folders:

This routine speaks for itself (use ONLY with building map_id's):
Code: [Select]
int CountBuildings(int player,map_id type)
{
   int cnt=0;
   Unit u;

   PlayerBuildingEnum enum1(player,type);
   while (enum1.GetNext(u)!=0)
     if (u.GetType()==type) ++cnt;
  
   return cnt;
}
« Last Edit: August 13, 2005, 02:18:53 PM by Eddy-B »
Rule #1:  Eddy is always right
Rule #2: If you think he's wrong, see rule #1
--------------------

Outpost : Renegades - Eddy-B.com - Electronics Pit[/siz

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4829
New Stuff
« Reply #1 on: August 14, 2005, 04:15:50 AM »
Hmm yes. Although, I'm sure there is a more efficient way to do that, but then, this is the most standard.

Offline BlackBox

  • Administrator
  • Hero Member
  • *****
  • Posts: 3101
New Stuff
« Reply #2 on: August 15, 2005, 07:27:07 AM »
Ok.... two questions on that one:

1. while (enum1.GetNext(u)!=0) should be changed to
while (enum1.GetNext(u)) because 0 is a false value, all other values are true. (The latter also generates more efficient machine code)

2. why do you need to check the type of each Unit that is returned? since the type is specified to the enumerator constructor. (So it would only return that specific type of unit).

I have some useful code too. Here's a couple functions.

Code: [Select]
__inline LOCATION GetMapSize() const
{
    // if your map HAPPENS to be bigger than 10000*10000, increase this
    MAP_RECT mr(0, 0, 10000, 10000);
    mr.ClipToMap();
    return LOCATION(mr.x2, mr.y2);
}

__inline LOCATION RandMapPt() const
{
    return GetMapSize().RandPt();
}

Those two functions return the dimensions of the map, and get a random point in the map, respectively. (The 2nd one depends on the 1st, so you need both if you're going to use random map points). There's probably a more efficient way to do it, but this is the best way to do it without having to hack into memory.

I marked the functions as __inline since they are relatively short and might be called repeatedly. (__inline, in the MS compiler, tells it to include the code from the function "in line" with the calling code. This is faster because the machine code instructions for pushing parameters to the function, calling it, and setting up and cleaning up the stack don't have to be done, because in the generated machine code there is no "subroutine.")

Anyway, for people who aren't used to __inline: There's few times when you should use it. On large functions with many calls it should never be used: the code for the function gets inserted multiple times, and your final executable size is a lot bigger.

For short functions that are a little bit more powerful than macros, which probably execute just as quickly as it takes to call the function, __inline is a good tool to speed up your code.
« Last Edit: August 15, 2005, 07:28:33 AM by op2hacker »

Offline Eddy-B

  • Hero Member
  • *****
  • Posts: 1194
    • http://www.eddy-b.com
New Stuff
« Reply #3 on: August 17, 2005, 01:16:58 PM »
Quote
1. while (enum1.GetNext(u)!=0) should be changed to
while (enum1.GetNext(u)) because 0 is a false value, all other values are true. (The latter also generates more efficient machine code)

2. why do you need to check the type of each Unit that is returned? since the type is specified to the enumerator constructor. (So it would only return that specific type of unit).
You are of course right. 1: i know this, but felt it was easier to understand for coding noobs. i don't think the speed will be effected more than a few nanoseconds bcoz of of it. 2: correct about that one. This is actually a copy of my unit-finder, which uses the UnitEnum to also find vehicles.


I have some more code that might proove useful (altho these are already included in my op2extra.dll project):

Code: [Select]
bool InRect(LOCATION loc,MAP_RECT rect)
{
  int temp;

  if (rect.x1>rect.x2)
  {
    temp=rect.x1;
    rect.x1=rect.x2;
    rect.x2=temp;
  }
  if (rect.y1>rect.y2)
  {
    temp=rect.y1;
    rect.y1=rect.y2;
    rect.y2=temp;
  }

  return ((loc.x>=rect.x1) && (loc.x<=rect.x2) && (loc.y>=rect.y1) && (loc.y<=rect.y2));
}

bool IsInRect(Unit u,MAP_RECT rect)
{
  return InRect(u.Location(),rect);
}
.. This is actual source taken from IUnit.cpp (with the IUnit:: class-prefix removed from the functions). If this can be optimized more.. lemme know!


Taken from my op2extra.cpp file:
Code: [Select]
void GetUnits(ScGroup &src,ScGroup &dest)
{
  Unit u;
  GroupEnumerator enum1(src);
  while (enum1.GetNext(u))
  {
    src.RemoveUnit(u);
    dest.TakeUnit(u);
  }
}

void GetUnits(MAP_RECT region,map_id type,map_id weapon,int playernum,ScGroup &dest)
{
  Unit u;
  InRectEnumerator enum1(region);
  while (enum1.GetNext(u))
  {
    if (u.OwnerID()!=playernum) continue;
    if ((type!=mapAny) && (u.GetType()!=type)) continue;
    if ((weapon!=mapAny) && (u.GetWeapon()!=weapon)) continue;
    
    dest.TakeUnit(u);
  }
}
The first one transfers units from 1 group to another. After testing a lot, it seemed TakeAllUnits was a little buggy, so i rewrote the routine (also not very efficient, but it works bugfree, compared to the ScGroup-one).
The second scans a rect for any units with the supplied params, and puts them in the group. Useful if you want to put new units into a group. This way you can use the CreateBase function, instead of defining the units one by one and adding them seperately. If you use mapAny for either of the params, it ignores either the unitType or the weaponType.
Rule #1:  Eddy is always right
Rule #2: If you think he's wrong, see rule #1
--------------------

Outpost : Renegades - Eddy-B.com - Electronics Pit[/siz