Black-Cell.net

  • December 17, 2018, 11:45:00 AM
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

News:

Pages: [1]   Go Down

Author Topic: Random working building selection  (Read 2754 times)

Reborn

  • Donator
  • Offline Offline
  • Posts: 200
    • View Profile
Random working building selection
« on: October 09, 2007, 05:08:47 PM »

I've tried srand and other library functions, but keep hitting a brick wall as I havn't got much experiance with random number generation.

What I want is a random, working GDI building function that returns the buildings position.

Something that would choose one of these at random:

Vector3 pp = Commands->Get_Position(Find_Power_Plant(1));
Vector3 ref = Commands->Get_Position(Find_Refinery(1));
Vector3 bar = Commands->Get_Position(Find_Soldier_Factory(1));
Vector3 weps = Commands->Get_Position(Find_War_Factory(1));
Vector3 agt = Commands->Get_Position(Find_Base_Defense(1));

Then check that the building was working, and if not choose another one at random (preferably missing out the one it just tried to select).

So when it has selected one at random, I can then do something like:

Vector3 position = /*the randomly selected building's position*/;


I've tried allot to make it work, but havn't had allot of experiance other then an example from a book about selecting a card from a pack and re-shuffling the cards. Which was helpful in as much as i'm sure I could make it choose another building from the array other then the one it tried selecting (assuming you would use an array in this instance, I think it should be done like that, but am very open to suggestions), but was mainly dealing with type int. So not useful too much in this instance.

Can you put me on the right track?
Logged

deathdish

  • Offline Offline
  • Posts: 925
    • View Profile
Re: Random working building selection
« Reply #1 on: October 10, 2007, 03:11:51 AM »

what language are you using? I'm not that great at programming, but you could generate a random number from 1 to 5 and assign 1, 2, 3, 4 and 5 to the five things you want to do
Logged

vloktboky

  • Offline Offline
  • Posts: 2631
    • View Profile
Re: Random working building selection
« Reply #2 on: October 10, 2007, 02:42:33 PM »

The golden rule for getting a random number in a range:

(rand() % (max - min + 1)) + min

Naturally, if you want a number in a range [0, x], then you can simplify it by simpling modulating the result of the rand() operation with x + 1 i.e. for a random number between [0, 5]: rand() % 6.

Because you want a single result, there is no way of escaping the nested condition trap. So calculate a random number between 0 and the total selection count, and check the result in an if/else statement.

Edit: I just noticed you were also wanting to avoid selecting a building that is dead. The slowest way to do that would be to just put it in a do/while loop and break out once you have a selection, getting a new random number each time through. If you want to know the faster way to do it, I can show you how to use bit masks and manipulations to always ensure you get a valid selection each time through.
« Last Edit: October 10, 2007, 02:45:17 PM by vloktboky »
Logged

Reborn

  • Donator
  • Offline Offline
  • Posts: 200
    • View Profile
Re: Random working building selection
« Reply #3 on: October 10, 2007, 05:23:14 PM »

Thanks for all the help everyone. I have made a good start on it now and am really happy. I feel really satisfied that I got it working.

If anyone is ever in a similar position (and I have learned to hat that word now, position), here is what I did to get a random building of GDI's:

Code: [Select]
int rand_0toN1(int n);
int rand_0toN1(int n){
return rand() % n;
}


Code: [Select]
void reb_Nod_Lear_Jet_strike::Timer_Expired(GameObject *obj, int number) {


// set seed for randomness
srand(time(NULL));

// define and declare my variable for the array
Vector3 pp = Commands->Get_Position(Find_Power_Plant(1));
Vector3 ref = Commands->Get_Position(Find_Refinery(1));
Vector3 bar = Commands->Get_Position(Find_Soldier_Factory(1));
Vector3 weps = Commands->Get_Position(Find_War_Factory(1));
Vector3 agt = Commands->Get_Position(Find_Base_Defense(1));

// initialise my array
Vector3 Buildings[5] = {pp,ref,bar,weps,agt};

// get a random number from 1 to 5 and set it to "t"
int t = rand_0toN1(5);

// position equals one of the five random buildings from my array
Vector3 position = Buildings[t];

I realise I need to check if the building is alive or not, and I also realise that it could be improved allot too, but it's a start that i'm happy with.
Logged

vloktboky

  • Offline Offline
  • Posts: 2631
    • View Profile
Re: Random working building selection
« Reply #4 on: October 10, 2007, 07:15:04 PM »

I advise against calling srand inside that function. That should be something you only call once at the beginning and never again. Everytime you reseed the rng in the C runtime library, it becomes more and more predictable.

The array idea is excellent. That was what I was going to suggest next, but you already figured it out, so good for you.
Logged

deathdish

  • Offline Offline
  • Posts: 925
    • View Profile
Re: Random working building selection
« Reply #5 on: October 11, 2007, 04:03:06 AM »

does srand () and srandom () have any difference?
Logged

Reborn

  • Donator
  • Offline Offline
  • Posts: 200
    • View Profile
Re: Random working building selection
« Reply #6 on: October 11, 2007, 04:54:48 AM »

Just when you think you've got it all worked out, more gloom and doom...

After the code has chosen a random Vector3 from the array I need to damage (or rather set_health, which takes a GameObject * type) of the building that the Vector3 has been based on.
There is no function that passes it back the other way. I thought I cracked it with "Find_Nearest_Building_To_Pos", but that function doesn't work how you might think :-(

I was rather pleased with myself for thinking, why don't I just make the array GameObject * types and then I can make a GameObject * variable that chooses one of the variables randomly from the array. Calling it something useful like "thebuilding".
After i've done that I can then get the building position using that variable, whilst still retaining my GameObject * to do the set_health stuff. I was so pleased with myself about this I actually dared to think it might work...

Let me show you a little more of what i'm actually doing here:


Code: [Select]
void reb_GDI_a10_strike::Timer_Expired(GameObject *obj, int number) {

srand(time(NULL));

GameObject *pp = Find_Power_Plant(0);
GameObject *ref = Find_Refinery(0);
GameObject *hand = Find_Soldier_Factory(0);
GameObject *strip = Find_Airstrip(0);
GameObject *ob = Find_Base_Defense(0);

GameObject *Buildings[5] = {pp,ref,hand,strip,ob};

int t = rand_0toN1(5);

GameObject *thebuilding = Buildings[t];

Vector3 position = Commands->Get_Position(thebuilding);

GameObject *a101;
a101 = Commands->Create_Object("Invisible_Object",position);

/* bunch of other if(number == n) crap that is irrelevant here */

// This cinematic makes an a-10 fly over and drop off a bomb. The bomb isn't real and has no effect on GameObjects *
if(number == 4){
Commands->Attach_Script(a101,"Test_Cinematic","A-10_bomb.txt");
}

/* bunch of other if(number == n) crap that is irrelevant here */

// I do this because I want the bomb to appear to have the effect of damaging the building it's being dropped off at.
if(number == 6){
Commands->Create_Explosion("Explosion_Mine_Timed_01",position,a101);
float buildinghealth = Commands->Get_Health(thebuilding);
Commands->Set_Health((thebuilding),(buildinghealth/2));
}
}



Now that all seems good to me. I jumped in game to check it out and it all starting going how it should do. I see the parachute drop off at a random building, i'm like "sweet dude". Then the wrong building gets it's health changed. I'm like "what the fuck dude?". I call the function a few more times and it happens all the time. A random buildings gets the damage that should be going to the same building where the cinematic is played.

I'm guessing the problem is with:

      float buildinghealth = Commands->Get_Health(thebuilding);
      Commands->Set_Health((thebuilding),(buildinghealth/2));

And that evertime I use that variable a new random building from the array is being called. I might be wrong, but I think that's a strong possibility.
Can anyone help me?
I feel like i've just climbed Everest only to find i'm actually only at the first peak.
Logged

vloktboky

  • Offline Offline
  • Posts: 2631
    • View Profile
Re: Random working building selection
« Reply #7 on: October 11, 2007, 06:13:29 AM »

Are you calling that function more than once, with number being a passed-in argument? If so, each time, you are getting a new random building. That's the nature of the functionality you wrote. "Give me a random building for number = 4." "Now, give me a new random building for number = 6."
Logged

bololo

  • Offline Offline
  • Posts: 4
    • View Profile
Re: Random working building selection
« Reply #8 on: October 11, 2007, 07:59:28 AM »

you could try this code:
Code: [Select]
void reb_GDI_a10_strike::Timer_Expired(GameObject *obj, int number) {

srand(time(NULL));

int t = rand_0toN1(4);
GameObject *thebuilding

switch( t )
  {     case 0: thebuilding = Find_Power_Plant(0);   break;
        case 1: thebuilding = Find_Refinery(0); break;
case 2: thebuilding = Find_Soldier_Factory(0); break;
case 3: thebuilding = Find_Airstrip(0); break;
case 4: thebuilding = Find_Base_Defense(0); break;


}

   if(number == 4)
   {
       //Commands->Attach_Script(a101,"Test_Cinematic","A-10_bomb.txt");
   }

   if(number == 6)
   {
      Commands->Create_Explosion("Explosion_Mine_Timed_01",Commands->Get_Position(thebuilding ),thebuilding );
      Commands->Set_Health(thebuilding ,Commands->Get_Health(thebuilding )/2);
   }
   
}

you may have to correct pointerassignments in the swich-command
because i am not sure about where to place the askerisk symbol and where not. ;)
« Last Edit: October 11, 2007, 08:09:43 AM by bololo »
Logged

bololo

  • Offline Offline
  • Posts: 4
    • View Profile
Re: Random working building selection
« Reply #9 on: October 11, 2007, 08:34:00 AM »

Code: [Select]
void reb_GDI_a10_strike::Timer_Expired(GameObject *obj, int number, int target)
{
GameObject *thebuilding
switch( target )
{
case 0: thebuilding = Find_Power_Plant(0);   break;
case 1: thebuilding = Find_Refinery(0); break;
case 2: thebuilding = Find_Soldier_Factory(0); break;
case 3: thebuilding = Find_Airstrip(0); break;
case 4: thebuilding = Find_Base_Defense(0); break;

}

   if(number == 4)
   {
       //Commands->Attach_Script(a101,"Test_Cinematic","A-10_bomb.txt");
   }

   if(number == 6)
   {
      Commands->Create_Explosion("Explosion_Mine_Timed_01",Commands->Get_Position(thebuilding ),thebuilding );
      Commands->Set_Health(thebuilding ,Commands->Get_Health(thebuilding )/2);
   }
   
}

if this does not work, i would remove the whole decision-stuff from this function and just make this function as slave that just playes the cinematic and removes health:

Somewhere in the calling block:
Code: [Select]
// decide outside the victim

GameObject *thebuilding
srand(time(NULL));
switch( rand_0toN1(4) )
{
case 0: thebuilding = Find_Power_Plant(0);   break;
case 1: thebuilding = Find_Refinery(0); break;
case 2: thebuilding = Find_Soldier_Factory(0); break;
case 3: thebuilding = Find_Airstrip(0); break;
case 4: thebuilding = Find_Base_Defense(0); break;

};
//call the function that animates and removes health
Timer_Expired(...,..., thebuilding)



And here what it does with the building:
Code: [Select]
void reb_GDI_a10_strike::Timer_Expired(GameObject *obj, GameObject * thebuilding)
{


   if(number == 4)
   {
       //Commands->Attach_Script(a101,"Test_Cinematic","A-10_bomb.txt");
   }

   if(number == 6)
   {
      Commands->Create_Explosion("Explosion_Mine_Timed_01",Commands->Get_Position(thebuilding ),thebuilding );
      Commands->Set_Health(thebuilding ,Commands->Get_Health(thebuilding )/2);
   }
   
}
« Last Edit: October 11, 2007, 08:44:18 AM by bololo »
Logged

bololo

  • Offline Offline
  • Posts: 4
    • View Profile
Re: Random working building selection
« Reply #10 on: October 11, 2007, 09:31:25 AM »

ok, forget the stuff above, here is the thingie that should work:

change the Created() like this:
Code: [Select]
void reb_GDI_a10_strike::Created(GameObject *obj)
{

char a10msg[128];
char a10msg2[128];
Commands->Create_2D_WAV_Sound("m00evan_dsgn0073i1evan_snd.wav");
sprintf(a10msg,"msg Warning!!!");
Console_Input(a10msg);
sprintf(a10msg2,"msg A-10 strike inbound at Nods position");
Console_Input(a10msg2);

srand(time(NULL));
GameObject *thebuilding

switch( rand_0toN1(4) )
{
case 0: thebuilding = Find_Power_Plant(0);   break;
case 1: thebuilding = Find_Refinery(0); break;
case 2: thebuilding = Find_Soldier_Factory(0); break;
case 3: thebuilding = Find_Airstrip(0); break;
case 4: thebuilding = Find_Base_Defense(0); break;
};


Commands->Start_Timer(thebuilding,this,3.0f,1);
Commands->Start_Timer(thebuilding,this,6.0f,2);
Commands->Start_Timer(thebuilding,this,9.0f,3);
Commands->Start_Timer(thebuilding,this,10.0f,4);
Commands->Start_Timer(thebuilding,this,17.5f,5);
Commands->Start_Timer(thebuilding,this,25.5f,6);
}

and the Timer_Expired like this:
Code: [Select]
void reb_GDI_a10_strike::Timer_Expired(GameObject *obj, int number) {
{


   if(number == 4)
   {
       Commands->Attach_Script(obj,"Test_Cinematic","A-10_bomb.txt");
   }

   if(number == 6)
   {
      Commands->Create_Explosion("Explosion_Mine_Timed_01",Commands->Get_Position(obj),obj);
      Commands->Set_Health(obj ,Commands->Get_Health(obj )/2);
   }
   
}

The clue is that you create a new object called thebuilding in the Created() function that will be the victim on all started timers from now. So all timer-expireings will work on that object. This has several advantages: This object does not not depend on the player that started anymore, (if player quits during countdown) and its very easy to adjust the code to gdi/nod, and check if building is already dead

Code: [Select]
do {
if (player-obj==gdi) {
switch( rand_0toN1(4) )
{
case 0: thebuilding = Find_Power_Plant(0);   break;
case 1: thebuilding = Find_Refinery(0); break;
case 2: thebuilding = Find_Soldier_Factory(0); break;
case 3: thebuilding = Find_Airstrip(0); break;
case 4: thebuilding = Find_Base_Defense(0); break;
};
}else
{
switch( rand_0toN1(4) )
{
case 0: thebuilding = Find_Power_Plant(1);   break;
case 1: thebuilding = Find_Refinery(1); break;
case 2: thebuilding = Find_Soldier_Factory(1); break;
case 3: thebuilding = Find_Airstrip(1); break;
case 4: thebuilding = Find_Base_Defense(1]); break;
};
}
}until thebuilding != alreadydestroyed

The disadvantage is that you loose the information WHO got the crate/initiated the airstrike, as we abuse the first parameter (gameobject) which is supposed to be the player as the victimbuilding.

best regards,
bololo
Logged

Reborn

  • Donator
  • Offline Offline
  • Posts: 200
    • View Profile
Re: Random working building selection
« Reply #11 on: October 11, 2007, 12:45:49 PM »

Excellent idea, but none of the timers are getting called this way.

Commands->Start_Timer does take a GameObject * as it's first parameter:

"void (*_Start_Timer) (GameObject *Obj,ScriptClass *Script,float Time,int Number);"

So maybe the switch isn't getting called?

Also, attaching scripts which attch a cinematic to "thebuilding" seems to be a less stable way then creating a GameObject * at its position then attaching a cinematic to that. I have experianced client crashes when attaching it to the building, but not when attaching it so a different GameObject. Perhaps buildings don't like cinematics attached to them :-/
« Last Edit: October 11, 2007, 12:56:22 PM by Reborn »
Logged

bololo

  • Offline Offline
  • Posts: 4
    • View Profile
Re: Random working building selection
« Reply #12 on: October 11, 2007, 03:30:54 PM »

i understand, then you have to use this temp object a101 like this:

Code: [Select]
void reb_GDI_a10_strike::Timer_Expired(GameObject *obj, int number) {
{
//given a pointer to the victimsbuilding : *obj of the parameters

//create a new object for cinematics at coodinates of the victimbuilding

GameObject *a101;
a101 = Commands->Create_Object("Invisible_Object",Commands->Get_Position(obj));

   //attach animations to a101
   if(number == 4)
   {
       Commands->Attach_Script(a101,"Test_Cinematic","A-10_bomb.txt");
   }

   //play cinematics at position of a101 and reduce health of victimbuilding (the *obj)
   if(number == 6)
   {
      Commands->Create_Explosion("Explosion_Mine_Timed_01",Commands->Get_Position(a101),a101);
      Commands->Set_Health(obj ,Commands->Get_Health(obj )/2);
   }
   
}

the Create() funcion must be like the previous posting
Logged

vloktboky

  • Offline Offline
  • Posts: 2631
    • View Profile
Re: Random working building selection
« Reply #13 on: October 11, 2007, 05:48:01 PM »

You're in a class. You don't have to rely on the signatures of these virtual functions. Use the class. Member variables are your friend.
Logged
Pages: [1]   Go Up