Black-Cell.net

  • September 21, 2018, 11:37:46 PM
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

News:

Pages: [1]   Go Down

Author Topic: Selecting a player at random ~ renegade API  (Read 1804 times)

Reborn

  • Donator
  • Offline Offline
  • Posts: 200
    • View Profile
Selecting a player at random ~ renegade API
« on: November 23, 2007, 03:59:13 PM »

I recently found myself needing to select a player at random, when someone joined the server. I thought I made a pretty nifty solution, however I assumed something I should not of done and have fallen on my ass a little bit.

This is how I was choosing a random player:

Code: [Select]
void virus_chooser::Created(GameObject *obj){
// get the player count of the server
int count = Get_Player_Count();
// if the player count is 0, then start a two second timer and look again in two seconds
if (count == 0){
Commands->Start_Timer(obj,this,2.0f,1);
}
// I used this condition because I found getting a random integer between 1 and 1 crashes the server
// otherwise I would not of bothered
// if the player count is 1 use this code
else if (count == 1){
// If the player count is 1, then there playerID will also be 1, so get there name assuming that there playerID is 1
GameObject *victim = Get_GameObj(count);
// Get there player name based on the gameobject
const char *Nick = Get_Player_Name(victim);
// Announce to the server that the pathogen has random infected the player
// although it isn't really random as there is only one player, lol
Console_Input(StrFormat("msg The pathogen has randomly infected: %s",Nick).c_str());
// attach the hunted player script to that player
Commands->Attach_Script(victim,"hunted_player","");
}
// Here is where the server really infects a random player
// if the player count is 2 players or more, then use this code
else if (count >= 2){
// get a random number between 1 and the total amount of players in the server
int Rnd = Commands->Get_Random_Int(1,count);
// Choose a player based on the random number generated bewteen 1 and the player count.
// This number must therefore be a valid PlayerID
GameObject *victim = Get_GameObj(Rnd);
// Get there name based on this random player
const char *Nick = Get_Player_Name(victim);
// announce that the pathogen has randomly infected the player
Console_Input(StrFormat("msg The pathogen has randomly infected: %s",Nick).c_str());
// attach the hunted player script to them
Commands->Attach_Script(victim,"hunted_player","");
}
}
// code to wait two seconds if the player count is 0
void virus_chooser::Timer_Expired(GameObject *obj, int number) {
if (number == 1){
Commands->Attach_Script(obj,"virus_chooser","");
}
}

My fatal flaw is that I assumed a player count also represents a valid range of playerID's. It doesn't. If someone leaves the server then there playerID goes with them, meaning that if someone else joins then the playerID range is one more then the player count, and with every person leaving and a new person joining the error compounds further.

I've had a few ideas of how to do this. But none that are very effiecient.

So what would you suggest so that I can efficiently choose a random player from the server?

Logged

deathdish

  • Offline Offline
  • Posts: 925
    • View Profile
Re: Selecting a player at random ~ renegade API
« Reply #1 on: November 23, 2007, 11:37:30 PM »

ooo i wonder what the maxium it is...

how about getting a random number with respect to maximum number, then modulo it with the number of players?
Logged

vloktboky

  • Offline Offline
  • Posts: 2631
    • View Profile
Re: Selecting a player at random ~ renegade API
« Reply #2 on: November 24, 2007, 06:39:46 AM »

That is already occurring and is hidden inside Get_Random_Int. His problem is he is using the random number directly as the player ID, which is valid from the start, but is incorrect later on. Player IDs are generated from an incremental source; they don't repeat.

You need to get the list of player objects and grab one from it. Where X is your random number, iterate through the list X number of steps.
Logged

deathdish

  • Offline Offline
  • Posts: 925
    • View Profile
Re: Selecting a player at random ~ renegade API
« Reply #3 on: November 25, 2007, 07:39:27 AM »

do you need to choose a random playerID i.e. if there were 5 players you want either 0, 1, 2, 3, 4 or 1, 2, 3, 4, 5(wherever you count from) or do you want their actual ID
Logged

Reborn

  • Donator
  • Offline Offline
  • Posts: 200
    • View Profile
Re: Selecting a player at random ~ renegade API
« Reply #4 on: November 25, 2007, 12:58:05 PM »

I am currently doing what you just said, that's the problem. By assuming that the player count represents a valid PlayerID range. So 5 players represents a range of 1,2,3,4 and 5. I then choose a random number of one to five to be the random player.

However that is a totally crap way of doing it because the player count only represents a true playerID range at the beginning.

I did think about otherways of doing it, but they are very inefficient and terribly sloppy.
I looked at how SSGM and jon_will's scripts.dll does it, and it's difficult to understand. I need to find out more about the type I guess.
extern SList<cPlayer *> *PlayerList; //Current player list
« Last Edit: November 25, 2007, 01:19:49 PM by Reborn »
Logged

vloktboky

  • Offline Offline
  • Posts: 2631
    • View Profile
Re: Selecting a player at random ~ renegade API
« Reply #5 on: November 25, 2007, 07:03:27 PM »

Yes, this SList object is a linked list. You want to iterate through that list a random number of steps to pull out a random player.

In Pseudocode:
SListIterator itPlayer = PlayerList->begin();
int nRandom = GetRandom(0,GetPlayerCount());
int nI = 0;
while (itPlayer != PlayerList->end()) // Safety, should never happen
{
    // Check if this is the random player, advance
    if (nI++ == nRandom)
    {
        return itPlayer->GetPlayer();
    }

    // Iterate
    itPlayer = itPlayer->next();
}

You want to go from the front of the list to the back of the list. You want to keep a count of how many steps you have walked through the list. You want to pull out the player who is X number of steps into the list.

A linked list stores data like this:
First --next--> Item2 --next--> Item3 --next--> Last --next--> NULL
Logged

Reborn

  • Donator
  • Offline Offline
  • Posts: 200
    • View Profile
Re: Selecting a player at random ~ renegade API
« Reply #6 on: November 26, 2007, 06:48:24 AM »

Ah, I need to go from the front to the back because it is a single element list right?
Each element is linked to the next, but not the previous. It is not bidirectional.
And it's extern because it's getting this list from either the game.exe or server.dat right?

And from this "typedef cPlayer *(*Find_Player) (int);" I can assume that cPlayer is type int right?
Logged

deathdish

  • Offline Offline
  • Posts: 925
    • View Profile
Re: Selecting a player at random ~ renegade API
« Reply #7 on: November 26, 2007, 08:49:09 AM »

hmm so you want the player's actual ID's right... yeh go vlokt's way
Logged
Pages: [1]   Go Up