Announcement

Collapse
No announcement yet.

Vote-Map: Add QuakeC to any mod

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Vote-Map: Add QuakeC to any mod

    The Legend of Bam Continues: Plug & Play Vote-Map Code



    Bam wrote some vote-map that can be easily be added to the QuakeC source of any mod to give the mod map voting capability. The code itself is modeled by the vote-map method that is used in RuneQuake.

    As most know, player map voting can make or break the popularity of any mod.

    1. No one likes to be stuck on an inappropriate map
    2. Players like to be in control on a server
    3. Admins are never around
    4. Giving someone an rcon password is dangerous, someone could change server settings
    Most of the popular mods have some form of map voting, but the burden upon a QuakeC coder to implement a map voting system is high and usually a foreign and rather technical and painful process for someone who typically is writing a mod for fun and doesn't want to be bogged down with figuring out "administrative code".

    This code has been tested with:

    ProQuake Server
    DarkPlaces Server
    And seems to work very well with both, so this can be applied to almost any mod where the QuakeC source is available.

    Features

    This code only uses a single impulse for voting.
    Vote for a map by typing the name of the map in the console.
    In theory, should support about 200 maps total.
    The code has been tested/added to debugged Bam/IEEE progs 1.06 and to the original rocket arena and it worked fine. The structure of some mods may vary slightly.

    The next post contains the instructions, which are very thorough just to make it clear what is being done, the actual changes themselves are some pretty mild stuff.
    Quakeone.com - Being exactly one-half good and one-half evil has advantages. When a portal opens to the antimatter universe, my opposite is just me with a goatee.

    So while you guys all have to fight your anti-matter counterparts, me and my evil twin will be drinking a beer laughing at you guys ...

  • #2
    Instructions

    Really the highlighted yellow code are the only changes, the whole function is shown for each change just to keep it obvious what is changing and make it clear.

    1. Add bindings.qc and vote.qc to your QuakeC source folder.

    Download: bindings.qc
    Download: vote.qc
    You will need to edit vote.qc if the mod or the server you intend to use this on is running something other than the standard Quake maps. The changes necessary are pretty obvious.
    Just keep in mind that you will need to change line 241 to expand/contract the impulse range if the number of voteable maps change:

    Line 241 of vote.qc will need changed if voteable maps are customized

    if (self.impulse >= 1 && self.impulse <= 38 )
    2. In progs.src, you need to add vote.qc and bindings.qc

    Add highlighted lines to your progs.src

    ../progs.dat

    defs.qc
    settings.qc // Add if this does not exist
    func.qc
    subs.qc
    fight.qc
    ai.qc
    combat.qc
    items.qc
    vote.qc // Must be before weapons.qc
    weapons.qc
    world.qc
    bindings.qc // Must be before client.qc
    client.qc
    player.qc
    monsters.qc
    doors.qc
    buttons.qc
    triggers.qc
    plats.qc
    misc.qc
    3. Add this to the end of defs.qc

    These are new variables and constants to support the vote-map functionality.

    Add to end of defs.qc

    //BAM ADD
    .float pflag, vflag;
    .float vdelay, vcount;
    .float primary_impulse_hack;
    string request_mapname;

    //==============
    // client.pflag
    //==============
    // client.pflag is used for random things to remember
    // about a player, and its value is saved across levels

    float POQ_NEW_CLIENT = 1;
    float POQ_BINDINGS_SENT = 2;
    float POQ_VOTE_IDENTIFY = 4;

    //==============
    // client.vflag
    //==============
    // client.vflag is used for voting

    float POQ_VOTE_YES = 1;
    float POQ_VOTE_NO = 2;
    4. Create or add this to settings.qc

    Adjust the impulses as appropriate for your mod. Your mod might already use these impulses or may prefer to change them. Impulses can be from 1 to 255, but generally the lower impulses are for weapons and such.

    Add to end of settings.qc, if settings.qc does not exist then create it.

    float VOTE_PRIMARY_IMPULSE = 97;
    float VOTE_YES_IMPULSE = 98;
    float VOTE_NO_IMPULSE = 99;
    float VOTE_PRINT_DELAY = 10;
    float VOTE_PRINT_COUNT = 5;
    5. Add this to the end of func.qc

    To support the new functions.

    Add to end of func.qc

    //BAM ADD
    void () vote_init_consider;
    void () vote_aliases;
    void (string s, void () func) vote_init;
    void (float print) vote_print;
    void (string mode_name, void () func) vote_spawn;
    6. Open Weapons.qc and modify as follows

    a. Find void() ImpulseCommands and highlighted text to an appropriate place in the if statements block.

    Add highlighted lines to ImpulseCommands in weapons.qc

    void() ImpulseCommands =
    {

    if (self.impulse >= 1 && self.impulse <= 8 )
    W_ChangeWeapon ();

    if (self.impulse == 9)
    CheatCommand ();
    if (self.impulse == 10)
    CycleWeaponCommand ();
    if (self.impulse == 11)
    ServerflagsCommand ();
    if (self.impulse == 12)
    CycleWeaponReverseCommand ();
    if (self.impulse == VOTE_YES_IMPULSE || self.impulse == VOTE_NO_IMPULSE)
    vote_impulse ();
    if (self.impulse == VOTE_PRIMARY_IMPULSE)
    {
    self.pflag = self.pflag | POQ_VOTE_IDENTIFY;
    self.primary_impulse_hack = time + 0.3;
    return;
    }


    if (self.impulse == 255)
    QuadCheat ();

    self.impulse = 0;
    };
    b. Find void() W_WeaponFrame and insert highlighted text.

    This is where the impulses that control map voting are checked.

    Add Highlighted code as follows to W_WeaponFrame in weapons.qc

    void() W_WeaponFrame =
    {
    if (time < self.attack_finished)
    return;

    if (self.impulse)
    {
    //BAM: Primary/Secondary vote impulse handling
    if (!self.pflag & POQ_VOTE_IDENTIFY)
    ImpulseCommands ();
    else
    {
    // BAM: If a player uses the primary impulse
    // (impulse <VOTE_PRIMARY_IMPULSE>) it goes into an endless loop.
    if (self.primary_impulse_hack < time)
    {
    self.pflag = self.pflag - (self.pflag & POQ_VOTE_IDENTIFY);
    self.impulse = 0;
    }
    else
    vote_init_consider ();
    }
    }


    // check for attack
    if (self.button0)
    {
    SuperDamageSound ();
    W_Attack ();
    }
    };
    7. Finally open client.qc for the following adjustments

    You may need to adjust this for some mods. This is where is bindings are sent to the client.

    The process works like this: a client connects and it will need the vote aliases sent to it and .pflag is keeps track of whether or not the aliases have been sent yet or not. This needs to preserve across map changes because clients only need the aliases sent once.

    If a client connects, it automatically needs them. If a client disconnects, this must be reset and the voting state of the client needs reset as well (.vflag).

    Near the top, preferably right before void() SetChangeParms add this function in client.qc

    void ()
    SetNewParms2 =
    {
    parm1 = IT_SHOTGUN | IT_AXE;
    parm2 = 100;
    parm3 = 0;
    parm4 = 25;
    parm5 = 0;
    parm6 = 0;
    parm7 = 0;
    parm8 = 1;
    parm9 = 0;
    parm10 = self.pflag;
    };
    Now in SetChangeParms, add the highlighted code

    void ()
    SetChangeParms =
    {
    if (self.health <= 0)
    {
    SetNewParms2 ();
    return;
    }

    //remove items
    self.items = self.items - (self.items &
    (IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY | IT_SUIT | IT_QUAD) );

    //cap super health
    if (self.health > 100)
    self.health = 100;
    if (self.health < 50)
    self.health = 50;
    parm1 = self.items;
    parm2 = self.health;
    parm3 = self.armorvalue;
    if (self.ammo_shells < 25)
    parm4 = 25;
    else
    parm4 = self.ammo_shells;
    parm5 = self.ammo_nails;
    parm6 = self.ammo_rockets;
    parm7 = self.ammo_cells;
    parm8 = self.weapon;
    parm9 = self.armortype * 100;
    parm10 = self.pflag;
    };
    Add this single highlighted line to SetNewParms in client.qc

    void ()
    SetNewParms =
    {
    parm1 = IT_SHOTGUN | IT_AXE;
    parm2 = 100;
    parm3 = 0;
    parm4 = 25;
    parm5 = 0;
    parm6 = 0;
    parm7 = 0;
    parm8 = 1;
    parm9 = 0;
    parm10 = POQ_NEW_CLIENT; // New client! They will need aliases sent!
    };
    Add/change highlighted lines in DecodeLevelParms in client.qc

    void ()
    DecodeLevelParms =
    {
    if (serverflags)
    {
    if (world.model == "maps/start.bsp")
    SetNewParms2 (); // This WAS SetNewParms(); but we are changing!
    }

    self.items = parm1;
    self.health = parm2;
    self.armorvalue = parm3;
    self.ammo_shells = parm4;
    self.ammo_nails = parm5;
    self.ammo_rockets = parm6;
    self.ammo_cells = parm7;
    self.weapon = parm8;
    self.armortype = parm9 * 0.01;
    self.pflag = parm10; // Need to preserve state of whether aliases have been sent
    };
    Change highlighted line in respawn in client.qc

    void ()
    respawn =
    {
    if (coop)
    {
    // make a copy of the dead body for appearances sake
    CopyToBodyQue (self);
    // get the spawn parms as they were at level start
    setspawnparms (self);
    // respawn
    PutClientInServer ();
    }
    else if (deathmatch)
    {
    // make a copy of the dead body for appearances sake
    CopyToBodyQue (self);
    // set default spawn parms
    SetNewParms2 (); // Was SetNewParms();
    // respawn
    PutClientInServer ();
    }
    else
    { // restart the entire server
    localcmd ("restart\n");
    }
    };
    Change code in ClientConnect in client.qc to mirror this

    void ()
    ClientConnect =
    {
    // a client connecting during an intermission can cause problems
    if (intermission_running)
    ExitIntermission ();

    if (parm10 & POQ_NEW_CLIENT) // this is a new client
    {
    bprint (self.netname); // Note these 2 lines have been moved
    bprint (" entered the game\n"); // to below the intermission check to ensure aliases are sent


    player_bindings_begin (); // send aliases
    parm10 = parm10 - POQ_NEW_CLIENT;
    }

    };
    Finally ...

    Add to end of ClientDisconnect in client.qc

    void ()
    ClientDisconnect =
    {
    if (gameover)
    return;
    // if the level end trigger has been activated, just return
    // since they aren't *really* leaving

    // let everyone else know
    bprint (self.netname);
    bprint (" left the game with ");
    bprint (ftos(self.frags));
    bprint (" frags\n");
    sound (self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE);
    set_suicide_frame ();
    self.pflag = 0; // Reset "alias sent" status
    self.vflag = 0; // Reset voting state (yes/no) status

    };
    Quakeone.com - Being exactly one-half good and one-half evil has advantages. When a portal opens to the antimatter universe, my opposite is just me with a goatee.

    So while you guys all have to fight your anti-matter counterparts, me and my evil twin will be drinking a beer laughing at you guys ...

    Comment


    • #3
      Very nice job Baker! You did a thorough explanation of the process. One thing I thought I might clear up is the usage of SetNewParms2(). I got the idea of using SetNewParms2() from CAx because it's the cleanest/simplest way to send bindings to a player.

      SetNewParms() is used to identify a new client connecting, because the engine calls this only once (when a new player connects)...but there are other lines that call this function in client.qc and we don't want this function being called more than once. So SetNewParms2() replaces the functionality of SetNewParms(), basically SetNewParms() is used for initiating settings for a new player and SetNewParms2() is for players who respawn.

      I hope that makes sense.

      Comment


      • #4
        I like it. It's nice. High five

        Comment


        • #5
          If only this was available a few weeks ago, I [possibly] wouldn't have had to bug Zop to put it in the DMP mod. Oh well, such is life. Much kudos to Bam and Baker.

          Kind regards

          Monty
          Mr.Burns
          "Helping to keep this community friendly, helpful, and clean of spammers since 2006"
          WWW: Quake Terminus , QuakeVoid You Tube: QuakeVoid
          Servers: Quake.shmack.net, damage.servequake.com

          News: JCR's excellent ctsj_jcr map is being ported to OOT

          Comment


          • #6
            My memory could serve me wrong on this but didn't RocketGuy or Lardarse help out with this vote-map thing since it was around the same time as the xctf mod? I just recall Baker mentioning the xctf vote-map code to me while playing in NewDM.
            Last edited by Canadian*Sniper; 10-03-2007, 07:51 PM.

            Comment


            • #7
              xCTF was written by Bam back in 2005 before this site existed. It had some simple vote-map code in it, but not as nice as this.
              Quakeone.com - Being exactly one-half good and one-half evil has advantages. When a portal opens to the antimatter universe, my opposite is just me with a goatee.

              So while you guys all have to fight your anti-matter counterparts, me and my evil twin will be drinking a beer laughing at you guys ...

              Comment


              • #8
                great job Bam/Baker! every mod needs this..

                Comment


                • #9
                  Uploaded this, mostly for Dreadful ...

                  Plain Old Quake w/Vote-Map: progs.dat + source

                  http://www.quake-1.com/files/sourcec...oq_votable.zip

                  With FrikQCC 2.5, I compiled it with frikqcc /O2 -allownest

                  No idea if Mac OS compilers work the same.

                  Note: This works fine on a dedicated server, but if you try to use it as a client OR with a dedicated server and client on the same machine, I recall that being iffy. Did a test with -dedicated on my Linux machine and connecting to it from my Windows machine and everything works perfect.
                  Quakeone.com - Being exactly one-half good and one-half evil has advantages. When a portal opens to the antimatter universe, my opposite is just me with a goatee.

                  So while you guys all have to fight your anti-matter counterparts, me and my evil twin will be drinking a beer laughing at you guys ...

                  Comment


                  • #10
                    Compiles flawlessly.
                    SpeakNow.QuakeOne.Com
                    [email protected]
                    AIM - EMHof1

                    Comment


                    • #11
                      In your mine of excellent help guides is there one which will give me a flawlessly compiling bit of code that will tell me how to port some of the Painkeep weapons into the DMP mod (flanders.servegame.org:26004) and add a vote-painkeep comand to enable/disable them (or make this an admin toggle)? Pleeeease :d

                      Even some guide that tells me how to create a series of new weapons so I can insert the appropriate code from the Painkeep source? Most of the ones I have seen at inside3d seem to convert existing ones which isn't tremendously helpful.

                      Or will the mighty Bam/RG/Zop/Rook/some other talented coder take pity on this QuakeC newbie and insert them for me ? We have the sources, we have the server, we have the updated DMP mod (thanks to Zop), we just need the Painkeep weapons to finish it off

                      If anyone can assist, point this QuakeC virgin in the right direction I would be very grateful.

                      Kind regards

                      Monty
                      Mr.Burns
                      "Helping to keep this community friendly, helpful, and clean of spammers since 2006"
                      WWW: Quake Terminus , QuakeVoid You Tube: QuakeVoid
                      Servers: Quake.shmack.net, damage.servequake.com

                      News: JCR's excellent ctsj_jcr map is being ported to OOT

                      Comment


                      • #12
                        ya... i dont have a func qc....what do i do>?

                        Comment


                        • #13
                          Originally posted by metchsteekle View Post
                          ya... i dont have a func qc....what do i do>?
                          Here is a standard progs 1.06 with vote-map.

                          It didn't have func.qc either. I can't recall if I made a func.qc or worked around it.

                          Source and progs: http://www.quake-1.com/files/sourcec...oq_votable.zip
                          Quakeone.com - Being exactly one-half good and one-half evil has advantages. When a portal opens to the antimatter universe, my opposite is just me with a goatee.

                          So while you guys all have to fight your anti-matter counterparts, me and my evil twin will be drinking a beer laughing at you guys ...

                          Comment


                          • #14
                            thanks ill have to get back to this modding again tomarrow

                            Comment


                            • #15
                              Just pile all the code in to vote.qc in the order listed in progs.src. It doesn't really make any difference whether you use one file or several as long as it's in the right order, and even that can be fudged in a variety of ways.
                              Qoetia B4 == 1.93Mb

                              Expo Booth '08
                              !AXATAXA! == 355.24 Kb Want to take on Quake with only your axe?
                              Hunting shamblers since 1996.

                              Comment

                              Working...
                              X