Adding Ladders

Discuss programming in the QuakeC language.
Post Reply
ScatterBox
Posts: 50
Joined: Sun Oct 13, 2013 7:53 pm

Adding Ladders

Post by ScatterBox »

Basically my mapper needs ladders coded in for the map to work properly, and I don't even know where to start. :/ I know that it should be pretty straight forward, but I'm just stuck. Any help would be appreciated. :|
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Adding Ladders

Post by Spike »

Engines with halflife support should support a func_wall entity with a .skin of -16 to mean 'this is a ladder', and give you physics that react accordingly, which is what I'd recommend for users of the FTE engine (this feature needs no qc changes, of course).
Sadly, this is not the same thing as halflife bsp support, as ladders tend to already have been hacked into various mods in vile horrendous and buggy ways - the pinnacle of which being extrasr4. Which will not work half the time, and leave you stuck in a wall for the rest.

If you want a generic solution that is 100% bug free, prepare for a lot of pain.
Essentually, you need to somehow disable gravity within the ladder area and to exagurate any up/down motion of the player, in order to allow the player free movement up and down the ladder by just looking+moving. Needing to use swimup+swimdown buttons just for a ladder is annoying, especially as people will expect +jump to move up instead, and will forget that swimup+down even exist.

If you want super-hacky-works-anywhere-but-super-lame ladders, then you can create a series of steps instead. 16qu up, 1qu in. at 1qu, the user is unlikely to notice that the ladder is actually steps. However, they will climb the ladder unreasonably fast and thus such 'ladders' should be kept small. These ladders are an easy hack, and do not require any qc or engine changes, can easily be attached to moving trains and platforms and doors and stuff, but they do suck so be aware of that. :P
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Adding Ladders

Post by frag.machine »

Spike wrote:If you want super-hacky-works-anywhere-but-super-lame ladders, then you can create a series of steps instead. 16qu up, 1qu in. at 1qu, the user is unlikely to notice that the ladder is actually steps. However, they will climb the ladder unreasonably fast and thus such 'ladders' should be kept small. These ladders are an easy hack, and do not require any qc or engine changes, can easily be attached to moving trains and platforms and doors and stuff, but they do suck so be aware of that. :P

Hmm, never occured me to make ladders this way. I made a quick test map, and indeed, they work in a too-silly-too-fast way, like some form of teleportation.
However, if you use a distance of 20 qu up between every step, the player is required to jump to advance 2 or 3 step at once, and doesn't look that bad - although I agree is far from the smooth half life support.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Adding Ladders

Post by leileilol »

I still don't understand why Half-Life 2 decided to do a worse ladder system...
i should not be here
Max_Salivan
Posts: 96
Joined: Thu Dec 15, 2011 1:00 pm

Re: Adding Ladders

Post by Max_Salivan »

Code: Select all

//
// LADDERS: Written by Frank Condello <pox@planetquake.com>
//
.float laddertime;
.float ladderjump;
float LADDEROFS = 0.36;// touchy...

// This is tricky cause we can't just check key presses...
void() ladder_touch =
{
        local vector vel;
        float fvel, spd;

        if (other.classname != "player") return;

        // FIXME! - time out for teleporters?

        // Don't stick underwater, or in the middle of a waterjump
        if (other.waterlevel > 1 || other.fwatershifttime > time) return;
        if (other.flags & FL_WATERJUMP) return;

        // Don't re-grab right away if jumping
        if (other.ladderjump > time) return;

        // Check if the player can grab the ladder
        makevectors (other.angles);
        if (v_forward*self.movedir<-0.5)// a little more than 180ј of freedom
                return;// not facing the right way

        // Avoid problems if the player is on the top edge (act like an 8 unit step)
        if (other.origin_z + other.mins_z + 8 >= self.absmax_z) {
                if ((!other.flags & FL_ONGROUND))
                        other.flags = other.flags + FL_ONGROUND;
                return;
        }

        // Null out gravity in PreThink
        other.laddertime = other.zerogtime = time + 0.1;
                // Stop all vertical movement
                other.velocity_z = 0;

                // Check if the player is moving sideways (don't go up/down)
                if (v_right*other.velocity > 25) {
                        other.velocity = '0 0 0';
                        other.origin = other.origin + v_right*0.5;// boost strafes
                        return;
                }
                else if (v_right*other.velocity < -25) {
                        other.velocity = '0 0 0';
                        other.origin = other.origin - v_right*0.5;// boost strafes
                        return;
                }

                // Get the player's forward speed
                fvel = v_forward*other.velocity;
//        }

        vel = '0 0 0';// Our new velocity

        // Up (facing up/forward)
        if (other.v_angle_x <= 15 && fvel>0 ) {
                other.origin = other.origin - self.movedir*LADDEROFS;// Pull back to keep from hitting the backing wall
                vel_z = fabs(other.v_angle_x)*6;// go faster when facing forward
                if (vel_z < 90) vel_z = 90;// minimum speed
        }
        // Up (facing down)
         else if ( other.v_angle_x >= 15 && fvel<0 ) {
                other.origin = other.origin + self.movedir*LADDEROFS;// Pull in to keep from falling off
                vel_z = other.v_angle_x*4;
        }
        // Down (facing up/forward)
        else if (other.v_angle_x <= 15 && fvel<0 ) {
                other.origin = other.origin + self.movedir*LADDEROFS;// Pull in to keep from falling off
                vel_z = fabs(other.v_angle_x)*-5;// go faster when facing forward
                if (vel_z > -80) vel_z = -80;// minimum speed
        }
        // Down (facing down)
        else if ( other.v_angle_x >= 15 && fvel>0 ) {
                other.origin = other.origin - self.movedir*LADDEROFS;// Pull back to keep from hitting the backing wall
                vel_z = other.v_angle_x*-4;
        }

        // Cap vertical moves to the server limits
        spd = 200;
        if (vel_z > spd) vel_z = spd;
        else if (vel_z < -1*spd) vel_z = -1*spd;

        // Add the parent's velocity - FIXME! - Physics on a moving ladder don't quite work
        //if (self.owner) vel = vel + self.owner.velocity;

        // Set the player's new veloctity
        other.velocity = vel;
};

/*QUAKED func_ladder (0 .5 .8) ?
Creates an invisible trigger area that the player can "climb" vertically.

Dependant on additions in client.qc, and player.qc

The movement was initially intended to mimic ladders in RTCW, but there
are some differences due to QuakeC limitations, and personal preference
(jumping behaviour and speed can easily be changed).

"angle" The direction the player must be facing in order to climb
"targetname" use as a killtarget to delete the ladder
DISABLED: "target" Attach the ladder to a func_train_ext

------------------------------------------------------------------------------------
BUGS:
- up/down keys don't climb (only way is to use MOVETYPE_FLY, which means current touch code is useless)
- DISABLED: physics break when the player is trying to move in the same direction as a ladder's parent train

------------------------------------------------------------------------------------
USEAGE NOTES:

These work best when they are at least 8 units thick.

Make sure the angle is set correctly. All movement revolves around the ladder's
facing angle. (Remember: It's the angle the PLAYER must be facing to climb)

The top of the func_ladder brush should be flush with the top of the ledge (if the
ladder leads to a ledge). Ladders behave as if there's an 8 unit "step" at the top.

It's a good idea to back these up with a solid brush or a clipping brush.
Especially if using real geometry for the rungs. (i.e. to fill the gaps between the rungs)

If you need a "two-way" ladder (like a ladder hanging from a fire-escape) use a clip
brush in the middle, and two func_ladders on either end with opposite facing angles.

Avoid situations where more than one func_ladder can be touched at the same time.

*/
void() func_ladder =
{
        InitTrigger();
        self.touch = ladder_touch;
};
buggy in Darkplaces,but working on another engines:)
for DP you need to do some changes
Sorry for my english :)
ScatterBox
Posts: 50
Joined: Sun Oct 13, 2013 7:53 pm

Re: Adding Ladders

Post by ScatterBox »

Max_Salivan wrote:

Code: Select all

//
// LADDERS: Written by Frank Condello <pox@planetquake.com>
//
.float laddertime;
.float ladderjump;
float LADDEROFS = 0.36;// touchy...

// This is tricky cause we can't just check key presses...
void() ladder_touch =
{
        local vector vel;
        float fvel, spd;

        if (other.classname != "player") return;

        // FIXME! - time out for teleporters?

        // Don't stick underwater, or in the middle of a waterjump
        if (other.waterlevel > 1 || other.fwatershifttime > time) return;
        if (other.flags & FL_WATERJUMP) return;

        // Don't re-grab right away if jumping
        if (other.ladderjump > time) return;

        // Check if the player can grab the ladder
        makevectors (other.angles);
        if (v_forward*self.movedir<-0.5)// a little more than 180ј of freedom
                return;// not facing the right way

        // Avoid problems if the player is on the top edge (act like an 8 unit step)
        if (other.origin_z + other.mins_z + 8 >= self.absmax_z) {
                if ((!other.flags & FL_ONGROUND))
                        other.flags = other.flags + FL_ONGROUND;
                return;
        }

        // Null out gravity in PreThink
        other.laddertime = other.zerogtime = time + 0.1;
                // Stop all vertical movement
                other.velocity_z = 0;

                // Check if the player is moving sideways (don't go up/down)
                if (v_right*other.velocity > 25) {
                        other.velocity = '0 0 0';
                        other.origin = other.origin + v_right*0.5;// boost strafes
                        return;
                }
                else if (v_right*other.velocity < -25) {
                        other.velocity = '0 0 0';
                        other.origin = other.origin - v_right*0.5;// boost strafes
                        return;
                }

                // Get the player's forward speed
                fvel = v_forward*other.velocity;
//        }

        vel = '0 0 0';// Our new velocity

        // Up (facing up/forward)
        if (other.v_angle_x <= 15 && fvel>0 ) {
                other.origin = other.origin - self.movedir*LADDEROFS;// Pull back to keep from hitting the backing wall
                vel_z = fabs(other.v_angle_x)*6;// go faster when facing forward
                if (vel_z < 90) vel_z = 90;// minimum speed
        }
        // Up (facing down)
         else if ( other.v_angle_x >= 15 && fvel<0 ) {
                other.origin = other.origin + self.movedir*LADDEROFS;// Pull in to keep from falling off
                vel_z = other.v_angle_x*4;
        }
        // Down (facing up/forward)
        else if (other.v_angle_x <= 15 && fvel<0 ) {
                other.origin = other.origin + self.movedir*LADDEROFS;// Pull in to keep from falling off
                vel_z = fabs(other.v_angle_x)*-5;// go faster when facing forward
                if (vel_z > -80) vel_z = -80;// minimum speed
        }
        // Down (facing down)
        else if ( other.v_angle_x >= 15 && fvel>0 ) {
                other.origin = other.origin - self.movedir*LADDEROFS;// Pull back to keep from hitting the backing wall
                vel_z = other.v_angle_x*-4;
        }

        // Cap vertical moves to the server limits
        spd = 200;
        if (vel_z > spd) vel_z = spd;
        else if (vel_z < -1*spd) vel_z = -1*spd;

        // Add the parent's velocity - FIXME! - Physics on a moving ladder don't quite work
        //if (self.owner) vel = vel + self.owner.velocity;

        // Set the player's new veloctity
        other.velocity = vel;
};

/*QUAKED func_ladder (0 .5 .8) ?
Creates an invisible trigger area that the player can "climb" vertically.

Dependant on additions in client.qc, and player.qc

The movement was initially intended to mimic ladders in RTCW, but there
are some differences due to QuakeC limitations, and personal preference
(jumping behaviour and speed can easily be changed).

"angle" The direction the player must be facing in order to climb
"targetname" use as a killtarget to delete the ladder
DISABLED: "target" Attach the ladder to a func_train_ext

------------------------------------------------------------------------------------
BUGS:
- up/down keys don't climb (only way is to use MOVETYPE_FLY, which means current touch code is useless)
- DISABLED: physics break when the player is trying to move in the same direction as a ladder's parent train

------------------------------------------------------------------------------------
USEAGE NOTES:

These work best when they are at least 8 units thick.

Make sure the angle is set correctly. All movement revolves around the ladder's
facing angle. (Remember: It's the angle the PLAYER must be facing to climb)

The top of the func_ladder brush should be flush with the top of the ledge (if the
ladder leads to a ledge). Ladders behave as if there's an 8 unit "step" at the top.

It's a good idea to back these up with a solid brush or a clipping brush.
Especially if using real geometry for the rungs. (i.e. to fill the gaps between the rungs)

If you need a "two-way" ladder (like a ladder hanging from a fire-escape) use a clip
brush in the middle, and two func_ladders on either end with opposite facing angles.

Avoid situations where more than one func_ladder can be touched at the same time.

*/
void() func_ladder =
{
        InitTrigger();
        self.touch = ladder_touch;
};
buggy in Darkplaces,but working on another engines:)
for DP you need to do some changes
Wow... you don't know how much this helped me!! I do get errors on "fwatershifttime" and "zerogtime" when I compile in fteqcc. But it should be simple to fix... maybe. Thanks!! :D :wink:

EDIT: I tested in my engine and the ladder work great!! :D Thanks a lot!
Cobalt
Posts: 445
Joined: Wed Jun 10, 2009 2:58 am
Location: New England, USA
Contact:

Re: Adding Ladders

Post by Cobalt »

Why not make one big custom sized trigger field that envelops the entire side of the ladder where the player would touch, as opposed to a touch field trigger for each bar? Seems to me movement would be the same as long as the player is within the bounds / touching of the trigger field.

You could also slow him down when he touches the bottom or top of the ladder by calculating the absmin/max of the field. When using DP, the .movement float might come in handy here too because its sensing the keys the client presses to move as I understand it.

Would also be neat if there were frames that represented the player climbing to give the full effect. self.fixangle = TRUE , also might be a good idea to turn on else yaw rotation might look strange when climbing a ladder if using a stock player mdl.
Chip
Posts: 575
Joined: Wed Jan 21, 2009 9:12 am
Location: Dublin, Ireland
Contact:

Re: Adding Ladders

Post by Chip »

I had a ladder function somewhere in an old mod, let me dig it up and share it with you.

I also had a nice video, but I lost it.
QuakeWiki
getButterfly - WordPress Support Services
Roo Holidays

Fear not the dark, but what the dark hides.
Nahuel
Posts: 495
Joined: Wed Jan 12, 2011 8:42 pm
Location: mar del plata

Re: Adding Ladders

Post by Nahuel »

better ladder are found in quoth (with multiple engine support, no bugs and perfect ), but the code is not released (i think the autors are using qc 1.06 , not really GPL code :lol: :lol: :lol: :lol: :lol: :P :P :P :P or they are using a misterious code from illuminati reptilian coders)
hi, I am nahuel, I love quake and qc.
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Re: Adding Ladders

Post by goldenboy »

The best QC ladders are in RMQ.

My pet theory why Quoth is closed source is that they are simply embarrassed because the code is horrible or because they grabbed so much stuff from Scourge of Armagon and a bunch of other mods. Being closed source also creates a bit of a mystery among the less well informed. :mrgreen:
Spiney
Posts: 63
Joined: Mon Feb 13, 2012 1:35 pm

Re: Adding Ladders

Post by Spiney »

goldenboy wrote:The best QC ladders are in RMQ.
They also seem broken sometimes in DP since I last tested.
But yeah, they work pretty well when they do.
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Adding Ladders

Post by leileilol »

Extras r4 ladders break in DP due to it being a dirty gravity hack... Quoth is allegedly a GPL violating closed source Extras r4 fork.
i should not be here
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Re: Adding Ladders

Post by goldenboy »

Spike fixed the RMQ ladders in July 2012 or something. I have no idea if that commit is in Schism.
Post Reply