From a802c3bf3ed13e295a02cd9cb8eff7a28b54fc2e Mon Sep 17 00:00:00 2001 From: Marco Hladik Date: Mon, 9 Sep 2019 18:55:58 +0200 Subject: [PATCH] func_train: implement most (if not all used) functionality. Needs more testing, but on the maps on which it does work, it seems to work well. Keep in mind that the player physics don't take ground entities into account yet - so you'll still bounce off the platforms when they're moving down, etc. That's a problem with the physics, but not the entity itself. --- src/gs-entbase/server.src | 4 +- src/gs-entbase/server/func_train.cpp | 201 ++++++++++++++++++-------- src/gs-entbase/server/path_corner.cpp | 44 +++++- 3 files changed, 187 insertions(+), 62 deletions(-) diff --git a/src/gs-entbase/server.src b/src/gs-entbase/server.src index b22496bd..3663b6d2 100644 --- a/src/gs-entbase/server.src +++ b/src/gs-entbase/server.src @@ -16,6 +16,8 @@ server/env_render.cpp server/env_shake.cpp server/env_message.cpp server/game_text.cpp +server/path_corner.cpp +server/path_track.cpp server/func_recharge.cpp server/func_healthcharger.cpp server/func_breakable.cpp @@ -52,8 +54,6 @@ server/env_shooter.cpp server/env_beverage.cpp server/env_global.cpp server/item_food.cpp -server/path_corner.cpp -server/path_track.cpp server/multi_manager.cpp server/monster_furniture.cpp server/monster_generic.cpp diff --git a/src/gs-entbase/server/func_train.cpp b/src/gs-entbase/server/func_train.cpp index 08efd163..862bab8a 100644 --- a/src/gs-entbase/server/func_train.cpp +++ b/src/gs-entbase/server/func_train.cpp @@ -14,131 +14,216 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/*QUAKED func_train (0 .5 .8) ? +/*QUAKED func_train (0 .5 .8) ? x x x TRAIN_NOTSOLID "targetname" Name -"target" Target when triggered. +"target" First node. "killtarget" Target to kill when triggered. +"dmg" Damage to inflict upon a person blocking the way. +"snd_move" Path to sound sample which plays when it's moving. +"snd_stop" Path to sound sample which plays when it stops moving. -Moving platform following along path_* entities. -Very unfinished. +Moving platform following along path_corner entities, aka nodes. +Most of its behaviour is controlled by the path_corner entities it passes over. +See the entity definition for path_corner to find out more. + +Upon level entry, the func_train will spawn right where its first path_corner +node is. This is so you can light the func_train somewhere else - like a lonely +box somewhere outside the playable area. */ +#define TRAIN_NOTSOLID 8 + +string g_strTrainMoveSnd[] = { + "common/null.wav", + "plats/bigmove1.wav", + "plats/bigmove2.wav", + "plats/elevmove1.wav", + "plats/elevmove2.wav", + "plats/elevmove3.wav", + "plats/freightmove1.wav", + "plats/freightmove2.wav", + "plats/heavymove1.wav", + "plats/rackmove1.wav", + "plats/railmove1.wav", + "plats/squeekmove1.wav", + "plats/talkmove1.wav", + "plats/talkmove2.wav" +}; +string g_strTrainStopSnd[] = { + "common/null.wav", + "plats/bigstop1.wav", + "plats/bigstop2.wav", + "plats/freightstop1.wav", + "plats/heavystop2.wav", + "plats/rackstop1.wav", + "plats/railstop1.wav", + "plats/squeekstop1.wav", + "plats/talkstop1.wav" +}; + class func_train:CBaseTrigger { + float m_flWait; float m_flSpeed; + float m_flDamage; + string m_strMoveSnd; + string m_strStopSnd; void() func_train; - virtual void() Find; virtual void() NextPath; virtual void() GoToTarget; virtual void() Trigger; virtual void() Respawn; + virtual void() Blocked; }; -void func_train::GoToTarget(void) +void +func_train::Blocked(void) { + Damage_Apply(other, this, m_flDamage, other.origin, TRUE); +} + +void +func_train::GoToTarget(void) +{ + entity eNode; float flTravelTime; - vector vel_to_pos; - entity f; + vector vecVelocity; + vector vecWorldPos; - f = find(world, CBaseTrigger::m_strTargetName, m_strTarget); + eNode = find(world, CBaseTrigger::m_strTargetName, m_strTarget); - if (!f) { - print("^1func_train^7: Trigger-Target not found! Removing.\n"); + if (!eNode) { return; } - vector vecWorldPos; vecWorldPos[0] = absmin[0] + (0.5 * (absmax[0] - absmin[0])); vecWorldPos[1] = absmin[1] + (0.5 * (absmax[1] - absmin[1])); vecWorldPos[2] = absmin[2] + (0.5 * (absmax[2] - absmin[2])); - vel_to_pos = (f.origin - vecWorldPos); - flTravelTime = (vlen(vel_to_pos) / m_flSpeed); + vecVelocity = (eNode.origin - vecWorldPos); + flTravelTime = (vlen(vecVelocity) / m_flSpeed); if (!flTravelTime) { NextPath(); - print(sprintf("TRAIN %s SPEED: %f\n", m_strTargetName, flTravelTime)); return; } - velocity = (vel_to_pos * (1 / flTravelTime)); + /* more stuff for the ears */ + if (m_strMoveSnd) { + sound(this, CHAN_VOICE, m_strMoveSnd, 1.0, ATTN_NORM); + } + + velocity = (vecVelocity * (1 / flTravelTime)); think = NextPath; nextthink = (ltime + flTravelTime); } -void func_train::NextPath(void) +void +func_train::NextPath(void) { - CBaseTrigger current_target; + path_corner eNode; + eNode = (path_corner)find(world, CBaseTrigger::m_strTargetName, m_strTarget); - print(sprintf("^2func_train^7: Talking to current target %s... ", m_strTarget)); - current_target = (CBaseTrigger)find(world, CBaseTrigger::m_strTargetName, m_strTarget); - - if (!current_target) { - print("^1FAILED.\n"); - } else { - print("^2SUCCESS.\n"); + if (!eNode) { + return; } - m_strTarget = current_target.m_strTarget; + /* fire the path_corners' target */ + if (eNode.m_strMessage) { + eNode.Trigger(); + } + + /* stuff for the ears */ + if (m_strStopSnd) { + sound(this, CHAN_BODY, m_strStopSnd, 1.0, ATTN_NORM); + } + /* make the loopy noise stop */ + if (m_strMoveSnd) { + sound(this, CHAN_VOICE, "common/null.wav", 0.0, ATTN_NORM); + } + + setorigin(this, eNode.origin - (mins + maxs) * 0.5); + m_flSpeed = eNode.m_flSpeed; + m_flWait = eNode.m_flWait; + m_strTarget = eNode.m_strTarget; velocity = [0,0,0]; - if (m_strTarget) { + /* warp */ + if (eNode.spawnflags & PC_TELEPORT) { + NextPath(); + return; + } + + /* stop until triggered again */ + if (eNode.spawnflags & PC_WAIT) { + return; + } + + if (m_flWait > 0) { + think = GoToTarget; + nextthink = ltime + m_flWait; + } else { GoToTarget(); } } -void func_train::Trigger(void) +void +func_train::Trigger(void) { GoToTarget(); } -void func_train::Find(void) +void +func_train::Respawn(void) { - entity f = find(world, CBaseTrigger::m_strTargetName, m_strTarget); - - if (!f) { - print(sprintf("^1func_train^7: End-Target %s not found! Removing.\n",m_strTarget)); - remove(this); - return; - } - - print("^2func_train^7: Successfully found first target.\n"); - vector vecWorldPos; - vecWorldPos[0] = absmin[0] + (0.5 * (absmax[0] - absmin[0])); - vecWorldPos[1] = absmin[1] + (0.5 * (absmax[1] - absmin[1])); - vecWorldPos[2] = absmin[2] + (0.5 * (absmax[2] - absmin[2])); - - vecWorldPos = f.origin - vecWorldPos; - setorigin(this, vecWorldPos); -} - -void func_train::Respawn(void) -{ - solid = SOLID_BSP; + solid = spawnflags & TRAIN_NOTSOLID ? SOLID_NOT : SOLID_BSP; movetype = MOVETYPE_PUSH; - //blocked = Blocked; - + blocked = Blocked; setmodel(this, m_oldModel); setorigin(this, m_oldOrigin); - /* Make sure we got some time for the paths to spawn */ - nextthink = ltime + 0.1f; - think = Find; + /* let's wait 1/4 a second to give the path_corner entities a chance to + * spawn in case they're after us in the ent lump */ + think = NextPath; + nextthink = ltime + 0.25f; } -void func_train::func_train(void) +void +func_train::func_train(void) { + int a; for (int i = 1; i < (tokenize(__fullspawndata) - 1); i += 2) { switch (argv(i)) { - case "speed": - m_flSpeed = stof(argv(i+1)); + case "dmg": + m_flDamage = stof(argv(i+1)); + break; + case "movesnd": + a = bound(0, stof(argv(i+1)), g_strTrainMoveSnd.length); + m_strMoveSnd = g_strTrainMoveSnd[a]; + break; + case "stopsnd": + a = bound(0, stof(argv(i+1)), g_strTrainStopSnd.length); + m_strStopSnd = g_strTrainStopSnd[a]; + break; + case "snd_move": + m_strMoveSnd = argv(i+1); + break; + case "snd_stop": + m_strStopSnd = argv(i+1); break; default: break; } } + if (m_strMoveSnd) { + precache_sound(m_strMoveSnd); + } + if (m_strStopSnd) { + precache_sound(m_strStopSnd); + } + if (!m_flSpeed) { m_flSpeed = 100; } diff --git a/src/gs-entbase/server/path_corner.cpp b/src/gs-entbase/server/path_corner.cpp index b33fa13a..9d1d2f18 100644 --- a/src/gs-entbase/server/path_corner.cpp +++ b/src/gs-entbase/server/path_corner.cpp @@ -22,17 +22,57 @@ STUB! */ +enumflags { + PC_WAIT, + PC_TELEPORT, + PC_FIREONCE +}; + class path_corner:CBaseTrigger { float m_flSpeed; + float m_flYawSpeed; float m_flWait; void() path_corner; + virtual void() Trigger; }; +void path_corner::Trigger(void) +{ + for ( entity eFind = world; ( eFind = find( eFind, CBaseTrigger::m_strTargetName, m_strMessage));) { + CBaseTrigger trigger = (CBaseTrigger) eFind; + trigger.Trigger(); + } +} + void path_corner::path_corner(void) { CBaseTrigger::CBaseTrigger(); - m_flSpeed = 100; - m_flWait = 1.0f; + + for ( int i = 1; i < ( tokenize( __fullspawndata ) - 1 ); i += 2 ) { + switch ( argv( i ) ) { + case "speed": + m_flSpeed = stof(argv( i + 1 )); + break; + case "yaw_speed": + m_flYawSpeed = stof(argv(i+1)); + break; + case "wait": + m_flWait = stof(argv( i + 1 )); + break; + case "message": + m_strMessage = argv( i + 1); + break; + default: + break; + } + } + + if (!m_flSpeed) + m_flSpeed = 100; + + if (!m_flWait) + m_flWait = 1.0f; + }