From 6d822acb289dcc0db4f100c8e8fc54aae09124c8 Mon Sep 17 00:00:00 2001 From: Juhu <5894800-Juhu_@users.noreply.gitlab.com> Date: Fri, 27 Jan 2023 12:26:35 +0100 Subject: [PATCH] q3df compat: add trigger_push_velocity support --- qcsrc/common/mapobjects/trigger/jumppads.qc | 217 +++++++++++++++++++- qcsrc/common/mapobjects/trigger/jumppads.qh | 18 ++ 2 files changed, 229 insertions(+), 6 deletions(-) diff --git a/qcsrc/common/mapobjects/trigger/jumppads.qc b/qcsrc/common/mapobjects/trigger/jumppads.qc index eee980618..46abdfded 100644 --- a/qcsrc/common/mapobjects/trigger/jumppads.qc +++ b/qcsrc/common/mapobjects/trigger/jumppads.qc @@ -14,6 +14,7 @@ void trigger_push_use(entity this, entity actor, entity trigger) #endif REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_PUSH) +REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_PUSH_VELOCITY) REGISTER_NET_LINKED(ENT_CLIENT_TARGET_PUSH) /* @@ -128,11 +129,110 @@ vector trigger_push_calculatevelocity(vector org, entity tgt, float ht, entity p return sdir * vs + '0 0 1' * vz; } -bool jumppad_push(entity this, entity targ) +vector trigger_push_velocity_calculatevelocity(entity this, vector org, entity tgt, float speed, float count, entity pushed_entity) +{ + vector sdir = normalize(vec2(pushed_entity.velocity)); + float zdir = copysign(1, pushed_entity.velocity.z); + if(pushed_entity.velocity.z == 0) zdir = 1; // copysign is negative on zero, we don't want that + + vector vs_tgt = '0 0 0'; + float vz_tgt = 0; + if (!(this.spawnflags & PLAYERDIR_XY) || !(this.spawnflags & PLAYERDIR_Z)) + { + vector vel_tgt = trigger_push_calculatevelocity(org, tgt, 0, pushed_entity); + vs_tgt = vec2(vel_tgt); + vz_tgt = vel_tgt.z; + + if (this.spawnflags & BIDIRECTIONAL_XY) + { + if (normalize(vs_tgt) * sdir < 0) + { + vs_tgt *= -1; + } + } + + if (this.spawnflags & BIDIRECTIONAL_Z) + { + if (signbit(vz_tgt) != signbit(zdir)) + { + vz_tgt *= -1; + } + } + } + + vector vs; + if (this.spawnflags & PLAYERDIR_XY) + { + vs = sdir * speed; + } + else + { + vs = vs_tgt; + } + + float vz; + if (this.spawnflags & PLAYERDIR_Z) + { + vz = zdir * count; + } + else + { + vz = vz_tgt; + } + + if (this.spawnflags & ADD_XY) + { + vs += vec2(pushed_entity.velocity); + if (this.spawnflags & CLAMP_NEGATIVE_ADDS) + { + if ((normalize(vs) * sdir) < 0) + { + vs = '0 0 0'; + } + } + } + + if (this.spawnflags & ADD_Z) + { + vz += pushed_entity.velocity.z; + if (this.spawnflags & CLAMP_NEGATIVE_ADDS) + { + if (signbit(vz) != signbit(zdir)) + { + vz = 0; + } + } + } + + return vs + '0 0 1' * vz; +} + +void check_pushed(entity this) +{ + IL_EACH(this.pushed, WarpZoneLib_ExactTrigger_Touch(this, it), + { + IL_REMOVE(this.pushed, it); + }); + if(!IL_EMPTY(this.pushed)) + { + this.nextthink = time; + } +} + +bool jumppad_push(entity this, entity targ, bool is_velocity_pad) { if (!isPushable(targ)) return false; + if(is_velocity_pad && IL_CONTAINS(this.pushed, targ)) + return false; + + if(is_velocity_pad) + { + IL_PUSH(this.pushed, targ); // may be briefly out of sync between client and server if client prediction is toggled + this.nextthink = time; + } + vector org = targ.origin; if(STAT(Q3COMPAT)) @@ -143,7 +243,14 @@ bool jumppad_push(entity this, entity targ) if(this.enemy) { - targ.velocity = trigger_push_calculatevelocity(org, this.enemy, this.height, targ); + if(!is_velocity_pad) + { + targ.velocity = trigger_push_calculatevelocity(org, this.enemy, this.height, targ); + } + else + { + targ.velocity = trigger_push_velocity_calculatevelocity(this, org, this.enemy, this.speed, this.count, targ); + } } else if(this.target && this.target != "") { @@ -156,11 +263,28 @@ bool jumppad_push(entity this, entity targ) else RandomSelection_AddEnt(e, 1, 1); } - targ.velocity = trigger_push_calculatevelocity(org, RandomSelection_chosen_ent, this.height, targ); + if(!is_velocity_pad) + { + targ.velocity = trigger_push_calculatevelocity(org, RandomSelection_chosen_ent, this.height, targ); + } + else + { + targ.velocity = trigger_push_velocity_calculatevelocity(this, org, RandomSelection_chosen_ent, this.speed, this.count, targ); + } } else { - targ.velocity = this.movedir; + if(!is_velocity_pad) + { + targ.velocity = this.movedir; + } + else + { +#ifdef SVQC + objerror (this, "Jumppad with no target"); +#endif + return false; + } } UNSET_ONGROUND(targ); @@ -268,7 +392,7 @@ void trigger_push_touch(entity this, entity toucher) EXACTTRIGGER_TOUCH(this, toucher); - noref bool success = jumppad_push(this, toucher); + noref bool success = jumppad_push(this, toucher, false); #ifdef SVQC if (success && (this.spawnflags & PUSH_ONCE)) @@ -280,6 +404,19 @@ void trigger_push_touch(entity this, entity toucher) #endif } +void trigger_push_velocity_touch(entity this, entity toucher) +{ + if (this.active == ACTIVE_NOT) + return; + + if(this.team && DIFF_TEAM(this, toucher)) + return; + + EXACTTRIGGER_TOUCH(this, toucher); + + noref bool success = jumppad_push(this, toucher, true); +} + #ifdef SVQC void trigger_push_link(entity this); void trigger_push_updatelink(entity this); @@ -575,6 +712,21 @@ float trigger_push_send(entity this, entity to, float sf) return true; } +float trigger_push_velocity_send(entity this, entity to, float sf) +{ + WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH_VELOCITY); + + WriteByte(MSG_ENTITY, this.team); + WriteInt24_t(MSG_ENTITY, this.spawnflags); + WriteByte(MSG_ENTITY, this.active); + WriteCoord(MSG_ENTITY, this.speed); + WriteCoord(MSG_ENTITY, this.count); + + trigger_common_write(this, true); + + return true; +} + void trigger_push_updatelink(entity this) { this.SendFlags |= SF_TRIGGER_INIT; @@ -585,6 +737,11 @@ void trigger_push_link(entity this) trigger_link(this, trigger_push_send); } +void trigger_push_velocity_link(entity this) +{ + trigger_link(this, trigger_push_velocity_send); +} + /* * ENTITY PARAMETERS: * @@ -624,6 +781,34 @@ spawnfunc(trigger_push) InitializeEntity(this, trigger_push_findtarget, INITPRIO_FINDTARGET); } +/* + * ENTITY PARAMETERS: + * + * target: this points to the target_position to which the player will jump. + * speed: XY speed for player-directional velocity pads - either sets or adds to the player's horizontal velocity. + * count: Z speed for player-directional velocity pads - either sets or adds to the player's vertical velocity. + */ +spawnfunc(trigger_push_velocity) +{ + SetMovedir(this); + + trigger_init(this); + + this.active = ACTIVE_ACTIVE; + this.use = trigger_push_use; + settouch(this, trigger_push_velocity_touch); + + // normal push setup + if (!this.noise) + this.noise = "misc/jumppad.wav"; + precache_sound (this.noise); + + trigger_push_velocity_link(this); // link it now + + this.pushed = IL_NEW(); + setthink(this, check_pushed); +} + bool target_push_send(entity this, entity to, float sf) { @@ -643,7 +828,7 @@ void target_push_use(entity this, entity actor, entity trigger) if(trigger.classname == "trigger_push" || trigger == this) return; // WTF, why is this a thing - jumppad_push(this, actor); + jumppad_push(this, actor, false); } void target_push_link(entity this) @@ -705,6 +890,26 @@ NET_HANDLE(ENT_CLIENT_TRIGGER_PUSH, bool isnew) return true; } +NET_HANDLE(ENT_CLIENT_TRIGGER_PUSH_VELOCITY, bool isnew) +{ + int mytm = ReadByte(); if(mytm) { this.team = mytm - 1; } + this.spawnflags = ReadInt24_t(); + this.active = ReadByte(); + this.speed = ReadCoord(); + this.count = ReadCoord(); + + trigger_common_read(this, true); + + this.entremove = trigger_remove_generic; + this.solid = SOLID_TRIGGER; + settouch(this, trigger_push_velocity_touch); + this.move_time = time; + this.pushed = IL_NEW(); + setthink(this, check_pushed); + + return true; +} + void target_push_remove(entity this) { // strfree(this.classname); diff --git a/qcsrc/common/mapobjects/trigger/jumppads.qh b/qcsrc/common/mapobjects/trigger/jumppads.qh index 268134e80..7be45ce93 100644 --- a/qcsrc/common/mapobjects/trigger/jumppads.qh +++ b/qcsrc/common/mapobjects/trigger/jumppads.qh @@ -4,12 +4,21 @@ const int PUSH_ONCE = BIT(0); // legacy, deactivate with relay instead const int PUSH_SILENT = BIT(1); // not used? +const int PLAYERDIR_XY = BIT(0); // if set, trigger will apply the horizontal speed in the player's horizontal direction of travel, otherwise it uses the target XY component. +const int ADD_XY = BIT(1); // if set, trigger will add to the player's horizontal velocity, otherwise it sets the player's horizontal velocity. +const int PLAYERDIR_Z = BIT(2); // if set, trigger will apply the vertical speed in the player's vertical direction of travel, otherwise it uses the target Z component. +const int ADD_Z = BIT(3); // if set, trigger will add to the player's vertical velocity, otherwise it sets the player's vertical velocity. +const int BIDIRECTIONAL_XY = BIT(4); // if set, non-playerdir velocity pads will function in 2 directions based on the target specified. The chosen direction is based on the current direction of travel. Applies to horizontal direction. +const int BIDIRECTIONAL_Z = BIT(5); // if set, non-playerdir velocity pads will function in 2 directions based on the target specified. The chosen direction is based on the current direction of travel. Applies to vertical direction. +const int CLAMP_NEGATIVE_ADDS = BIT(6); // if set, then a velocity pad that adds negative velocity will be clamped to 0, if the resultant velocity would bounce the player in the opposite direction. + IntrusiveList g_jumppads; STATIC_INIT(g_jumppads) { g_jumppads = IL_NEW(); } .float pushltime; .bool istypefrag; .float height; +.IntrusiveList pushed; const int NUM_JUMPPADSUSED = 3; .float jumppadcount; @@ -54,8 +63,17 @@ void trigger_push_findtarget(entity this); * values to target a point on the ceiling. * movedir: if target is not set, this * speed * 10 is the velocity to be reached. */ + +/* + * ENTITY PARAMETERS: + * + * target: this points to the target_position to which the player will jump. + * speed: XY speed for player-directional velocity pads - either sets or adds to the player's horizontal velocity. + * count: Z speed for player-directional velocity pads - either sets or adds to the player's vertical velocity. + */ #ifdef SVQC spawnfunc(trigger_push); +spawnfunc(trigger_push_velocity); spawnfunc(target_push); spawnfunc(info_notnull); -- 2.39.2