From: Mario Date: Wed, 28 Jan 2015 09:39:38 +0000 (+1100) Subject: The end of the start X-Git-Tag: xonotic-v0.8.1~38^2~44 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=f7587ab3e768db3977648bfe532e39fe445bb8c0;p=xonotic%2Fxonotic-data.pk3dir.git The end of the start --- diff --git a/qcsrc/client/Main.qc b/qcsrc/client/Main.qc index fcb25246f..f163ad73a 100644 --- a/qcsrc/client/Main.qc +++ b/qcsrc/client/Main.qc @@ -351,6 +351,14 @@ void trigger_touch_generic(void() touchfunc) } } } +void trigger_draw_generic() +{ + float dt = time - self.move_time; + self.move_time = time; + if(dt <= 0) { return; } + + if(self.trigger_touch) { trigger_touch_generic(self.trigger_touch); } +} void Ent_RemoveEntCS() { @@ -855,6 +863,8 @@ void CSQC_Ent_Update(float bIsNewEntity) case ENT_CLIENT_TRIGGER_PUSH: ent_trigger_push(); break; case ENT_CLIENT_TARGET_PUSH: ent_target_push(); break; case ENT_CLIENT_CONVEYOR: ent_conveyor(); break; + case ENT_CLIENT_DOOR: ent_door(); break; + case ENT_CLIENT_DOOR_TRIGGER: ent_door_trigger(); break; default: //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype)); diff --git a/qcsrc/client/bgmscript.qh b/qcsrc/client/bgmscript.qh index 713cf5798..e31830552 100644 --- a/qcsrc/client/bgmscript.qh +++ b/qcsrc/client/bgmscript.qh @@ -1,9 +1,3 @@ -.string bgmscript; -.float bgmscriptattack; -.float bgmscriptdecay; -.float bgmscriptsustain; -.float bgmscriptrelease; - .float just_toggled; void BGMScript_InitEntity(entity e); diff --git a/qcsrc/client/effects.qc b/qcsrc/client/effects.qc index c35a3a94a..4aa65f3ec 100644 --- a/qcsrc/client/effects.qc +++ b/qcsrc/client/effects.qc @@ -5,9 +5,6 @@ .string fx_texture; .float fx_lifetime; -void SUB_Remove() -{ remove(self); } - void b_draw() { //Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, 0, time * 3, '1 1 1', 0.7, DRAWFLAG_ADDITIVE, view_origin); diff --git a/qcsrc/client/progs.src b/qcsrc/client/progs.src index e414576c3..0e6a4e962 100644 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@ -62,6 +62,8 @@ vehicles/vehicles.qh weapons/projectile.qh // TODO player_skeleton.qh +../common/triggers/include.qh + sortlist.qc miscfunctions.qc ../server/t_items.qh @@ -131,6 +133,8 @@ command/cl_cmd.qc ../common/buffs.qc ../common/physics.qc +../common/triggers/include.qc + ../warpzonelib/anglestransform.qc ../warpzonelib/mathlib.qc ../warpzonelib/common.qc diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index 28cf97f5d..054364f12 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -104,6 +104,8 @@ const float ENT_CLIENT_LADDER = 61; const float ENT_CLIENT_TRIGGER_PUSH = 62; const float ENT_CLIENT_TARGET_PUSH = 63; const float ENT_CLIENT_CONVEYOR = 64; +const float ENT_CLIENT_DOOR = 65; +const float ENT_CLIENT_DOOR_TRIGGER = 66; const float ENT_CLIENT_HEALING_ORB = 80; diff --git a/qcsrc/common/net_notice.qc b/qcsrc/common/net_notice.qc index caaae8b49..e9d86420f 100644 --- a/qcsrc/common/net_notice.qc +++ b/qcsrc/common/net_notice.qc @@ -45,9 +45,6 @@ void sv_notice_toall(string _notice, float _howlong, float _modal) #endif // SVQC #ifdef CSQC -void SUB_Remove() -{ remove(self); } - void cl_notice_read() { entity _notice; diff --git a/qcsrc/common/triggers/f_door.qc b/qcsrc/common/triggers/f_door.qc index 172628b60..a1b1440ab 100644 --- a/qcsrc/common/triggers/f_door.qc +++ b/qcsrc/common/triggers/f_door.qc @@ -27,19 +27,25 @@ void() door_rotating_go_up; void door_blocked() { + if((self.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) + { // KIll Kill Kill!! +#ifdef SVQC + Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0'); +#endif + } + else + { +#ifdef SVQC + if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite? + Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0'); +#endif - if((self.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!! - Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0'); - } else { - - if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite? - Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0'); - - //Dont chamge direction for dead or dying stuff - if(other.deadflag != DEAD_NO && (other.takedamage == DAMAGE_NO)) { - if (self.wait >= 0) - { - if (self.state == STATE_DOWN) + //Dont chamge direction for dead or dying stuff + if(PHYS_DEAD(other) && (other.takedamage == DAMAGE_NO)) + { + if (self.wait >= 0) + { + if (self.state == STATE_DOWN) if (self.classname == "door") { door_go_up (); @@ -47,7 +53,7 @@ void door_blocked() { door_rotating_go_up (); } - else + else if (self.classname == "door") { door_go_down (); @@ -55,13 +61,17 @@ void door_blocked() { door_rotating_go_down (); } - } - } else { - //gib dying stuff just to make sure - if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite? - Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0'); - } - } + } + } +#ifdef SVQC + else + { + //gib dying stuff just to make sure + if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite? + Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0'); + } +#endif + } } void door_hit_top() @@ -134,7 +144,8 @@ ACTIVATION FUNCTIONS ============================================================================= */ -float door_check_keys(void) { +float door_check_keys(void) +{ local entity door; @@ -152,28 +163,41 @@ float door_check_keys(void) { if (!IS_PLAYER(other)) return FALSE; - if (item_keys_usekey(door, other)) { + if (item_keys_usekey(door, other)) + { // some keys were used - if (other.key_door_messagetime <= time) { + if (other.key_door_messagetime <= time) + { +#ifdef SVQC play2(other, "misc/talk.wav"); Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(door.itemkeys)); +#endif other.key_door_messagetime = time + 2; } - } else { + } + else + { // no keys were used - if (other.key_door_messagetime <= time) { + if (other.key_door_messagetime <= time) + { +#ifdef SVQC play2(other, "misc/talk.wav"); Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(door.itemkeys)); +#endif other.key_door_messagetime = time + 2; } } - if (door.itemkeys) { + if (door.itemkeys) + { +#ifdef SVQC // door is now unlocked play2(other, "misc/talk.wav"); Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_UNLOCKED); +#endif return TRUE; - } else + } + else return FALSE; } @@ -222,11 +246,11 @@ void door_fire() if ((self.spawnflags & 2) && other.trigger_reverse!=0 && self.lip!=666 && self.state == STATE_BOTTOM) { self.lip = 666; // self.lip is used to remember reverse opening direction for door_rotating - self.pos2 = '0 0 0' - self.pos2; + self.pos2 = '0 0 0' - self.pos2; } // if BIDIR_IN_DOWN (==8) is set, prevent the door from reoping during closing if it is triggered from the wrong side if (!((self.spawnflags & 2) && (self.spawnflags & 8) && self.state == STATE_DOWN - && (((self.lip==666) && (other.trigger_reverse==0)) || ((self.lip!=666) && (other.trigger_reverse!=0))))) + && (((self.lip==666) && (other.trigger_reverse==0)) || ((self.lip!=666) && (other.trigger_reverse!=0))))) { door_rotating_go_up (); } @@ -251,27 +275,6 @@ void door_use() } } -void door_trigger_touch() -{ - if (other.health < 1) - if (!(other.iscreature && other.deadflag == DEAD_NO)) - return; - - if (time < self.attack_finished_single) - return; - - // check if door is locked - if (!door_check_keys()) - return; - - self.attack_finished_single = time + 1; - - activator = other; - - self = self.owner; - door_use (); -} - void door_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { entity oself; @@ -280,7 +283,8 @@ void door_damage(entity inflictor, entity attacker, float damage, float deathtyp return; self.health = self.health - damage; - if (self.itemkeys) { + if (self.itemkeys) + { // don't allow opening doors through damage if keys are required return; } @@ -314,39 +318,52 @@ void door_touch() self.owner.attack_finished_single = time + 2; +#ifdef SVQC if (!(self.owner.dmg) && (self.owner.message != "")) { if (IS_CLIENT(other)) centerprint(other, self.owner.message); play2(other, "misc/talk.wav"); } +#endif } void door_generic_plat_blocked() { - if((self.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!! - Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0'); - } else { - - if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite? - Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0'); - - //Dont chamge direction for dead or dying stuff - if(other.deadflag != DEAD_NO && (other.takedamage == DAMAGE_NO)) { - if (self.wait >= 0) - { - if (self.state == STATE_DOWN) - door_rotating_go_up (); - else - door_rotating_go_down (); - } - } else { - //gib dying stuff just to make sure - if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite? - Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0'); - } - } + if((self.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!! +#ifdef SVQC + Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0'); +#endif + } + else + { + +#ifdef SVQC + if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite? + Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0'); +#endif + + //Dont chamge direction for dead or dying stuff + if(PHYS_DEAD(other) && (other.takedamage == DAMAGE_NO)) + { + if (self.wait >= 0) + { + if (self.state == STATE_DOWN) + door_rotating_go_up (); + else + door_rotating_go_down (); + } + } +#ifdef SVQC + else + { + //gib dying stuff just to make sure + if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite? + Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0'); + } +#endif + } } void door_rotating_hit_top() @@ -410,17 +427,68 @@ void door_rotating_go_up() /* -============================================================================= +========================================= +door trigger -SPAWNING FUNCTIONS - -============================================================================= +Spawned if a door lacks a real activator +========================================= */ -entity spawn_field(vector fmins, vector fmaxs) +void door_trigger_touch() +{ + if (other.health < 1) +#ifdef SVQC + if (!(other.iscreature && !PHYS_DEAD(other))) +#elif defined(CSQC) + if(!(IS_CLIENT(other) && !PHYS_DEAD(other))) + return; +#endif + + if (time < self.attack_finished_single) + return; + + // check if door is locked + if (!door_check_keys()) + return; + + self.attack_finished_single = time + 1; + + activator = other; + + self = self.owner; + door_use (); +} + +#ifdef SVQC + +float door_trigger_send(entity to, float sf) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_DOOR_TRIGGER); + + WriteShort(MSG_ENTITY, num_for_edict(self.owner)); + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + + WriteCoord(MSG_ENTITY, self.mins_x); + WriteCoord(MSG_ENTITY, self.mins_y); + WriteCoord(MSG_ENTITY, self.mins_z); + WriteCoord(MSG_ENTITY, self.maxs_x); + WriteCoord(MSG_ENTITY, self.maxs_y); + WriteCoord(MSG_ENTITY, self.maxs_z); + + return TRUE; +} + +void door_trigger_link(entity trig) +{ + Net_LinkEntity(trig, FALSE, 0, door_trigger_send); +} + +void spawn_field(vector fmins, vector fmaxs) { entity trigger; - vector t1, t2; + vector t1 = fmins, t2 = fmaxs; trigger = spawn(); trigger.classname = "doortriggerfield"; @@ -429,12 +497,47 @@ entity spawn_field(vector fmins, vector fmaxs) trigger.owner = self; trigger.touch = door_trigger_touch; - t1 = fmins; - t2 = fmaxs; setsize (trigger, t1 - '60 60 8', t2 + '60 60 8'); - return (trigger); + door_trigger_link(trigger); +} + +#elif defined(CSQC) + +void ent_door_trigger() +{ + float entnum = ReadShort(); + self.origin_x = ReadCoord(); + self.origin_y = ReadCoord(); + self.origin_z = ReadCoord(); + setorigin(self, self.origin); + self.mins_x = ReadCoord(); + self.mins_y = ReadCoord(); + self.mins_z = ReadCoord(); + self.maxs_x = ReadCoord(); + self.maxs_y = ReadCoord(); + self.maxs_z = ReadCoord(); + setsize(self, self.mins, self.maxs); + + self.owner = findfloat(world, sv_entnum, entnum); // if owner doesn't exist, it shouldn't matter much + self.classname = "doortriggerfield"; + self.movetype = MOVETYPE_NONE; + self.solid = SOLID_TRIGGER; + self.trigger_touch = door_trigger_touch; + self.draw = trigger_draw_generic; + self.drawmask = MASK_NORMAL; + self.move_time = time; } +#endif +#ifdef SVQC +/* +============= +LinkDoors + + +============= +*/ + entity LinkDoors_nextent(entity cur, entity near, entity pass) { while((cur = find(cur, classname, self.classname)) && ((cur.spawnflags & 4) || cur.enemy)) @@ -446,35 +549,24 @@ entity LinkDoors_nextent(entity cur, entity near, entity pass) float LinkDoors_isconnected(entity e1, entity e2, entity pass) { float DELTA = 4; - if (e1.absmin_x > e2.absmax_x + DELTA) - return FALSE; - if (e1.absmin_y > e2.absmax_y + DELTA) - return FALSE; - if (e1.absmin_z > e2.absmax_z + DELTA) - return FALSE; - if (e2.absmin_x > e1.absmax_x + DELTA) - return FALSE; - if (e2.absmin_y > e1.absmax_y + DELTA) - return FALSE; - if (e2.absmin_z > e1.absmax_z + DELTA) - return FALSE; + if((e1.absmin_x > e2.absmax_x + DELTA) + || (e1.absmin_y > e2.absmax_y + DELTA) + || (e1.absmin_z > e2.absmax_z + DELTA) + || (e2.absmin_x > e1.absmax_x + DELTA) + || (e2.absmin_y > e1.absmax_y + DELTA) + || (e2.absmin_z > e1.absmax_z + DELTA) + ) { return FALSE; } return TRUE; } - -/* -============= -LinkDoors - - -============= -*/ - +void door_link(); void LinkDoors() { entity t; vector cmins, cmaxs; + door_link(); + if (self.enemy) return; // already linked by another door if (self.spawnflags & 4) @@ -487,7 +579,7 @@ void LinkDoors() return; if (self.items) return; - self.trigger_field = spawn_field(self.absmin, self.absmax); + spawn_field(self.absmin, self.absmax); return; // don't want to link this door } @@ -555,7 +647,7 @@ void LinkDoors() if (self.items) return; - self.trigger_field = spawn_field(cmins, cmaxs); + spawn_field(cmins, cmaxs); } @@ -588,6 +680,55 @@ FIXME: only one sound set available at the time being */ +float door_send(entity to, float sf) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_DOOR); + + WriteShort(MSG_ENTITY, num_for_edict(self)); + WriteByte(MSG_ENTITY, self.warpzone_isboxy); + WriteByte(MSG_ENTITY, self.skin); + WriteByte(MSG_ENTITY, self.speed); + WriteByte(MSG_ENTITY, self.scale); + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + + WriteCoord(MSG_ENTITY, self.mins_x); + WriteCoord(MSG_ENTITY, self.mins_y); + WriteCoord(MSG_ENTITY, self.mins_z); + WriteCoord(MSG_ENTITY, self.maxs_x); + WriteCoord(MSG_ENTITY, self.maxs_y); + WriteCoord(MSG_ENTITY, self.maxs_z); + + WriteCoord(MSG_ENTITY, self.movedir_x); + WriteCoord(MSG_ENTITY, self.movedir_y); + WriteCoord(MSG_ENTITY, self.movedir_z); + + WriteCoord(MSG_ENTITY, self.angles_x); + WriteCoord(MSG_ENTITY, self.angles_y); + WriteCoord(MSG_ENTITY, self.angles_z); + + WriteCoord(MSG_ENTITY, self.pos1_x); + WriteCoord(MSG_ENTITY, self.pos1_y); + WriteCoord(MSG_ENTITY, self.pos1_z); + WriteCoord(MSG_ENTITY, self.pos2_x); + WriteCoord(MSG_ENTITY, self.pos2_y); + WriteCoord(MSG_ENTITY, self.pos2_z); + + WriteCoord(MSG_ENTITY, self.size_x); + WriteCoord(MSG_ENTITY, self.size_y); + WriteCoord(MSG_ENTITY, self.size_z); + + WriteByte(MSG_ENTITY, self.wait); + + return TRUE; +} + +void door_link() +{ + Net_LinkEntity(self, FALSE, 0, door_send); +} + void door_init_startopen() { setorigin (self, self.pos2); @@ -624,9 +765,9 @@ void spawnfunc_func_door() self.blocked = door_blocked; self.use = door_use; - if(self.dmg && (self.message == "")) + if(self.dmg && (self.message == "")) self.message = "was squished"; - if(self.dmg && (self.message2 == "")) + if(self.dmg && (self.message2 == "")) self.message2 = "was squished by"; if (self.sounds > 0) @@ -671,3 +812,59 @@ void spawnfunc_func_door() self.reset = door_reset; } + +#elif defined(CSQC) + +void door_draw() +{ + float dt = time - self.move_time; + self.move_time = time; + if(dt <= 0) { return; } + + trigger_touch_generic(door_touch); +} + +void ent_door() +{ + self.sv_entnum = ReadShort(); + self.warpzone_isboxy = ReadByte(); + self.skin = ReadByte(); + self.speed = ReadByte(); + self.scale = ReadByte(); + self.origin_x = ReadCoord(); + self.origin_y = ReadCoord(); + self.origin_z = ReadCoord(); + setorigin(self, self.origin); + self.mins_x = ReadCoord(); + self.mins_y = ReadCoord(); + self.mins_z = ReadCoord(); + self.maxs_x = ReadCoord(); + self.maxs_y = ReadCoord(); + self.maxs_z = ReadCoord(); + setsize(self, self.mins, self.maxs); + self.movedir_x = ReadCoord(); + self.movedir_y = ReadCoord(); + self.movedir_z = ReadCoord(); + self.angles_x = ReadCoord(); + self.angles_y = ReadCoord(); + self.angles_z = ReadCoord(); + self.pos1_x = ReadCoord(); + self.pos1_y = ReadCoord(); + self.pos1_z = ReadCoord(); + self.pos2_x = ReadCoord(); + self.pos2_y = ReadCoord(); + self.pos2_z = ReadCoord(); + self.size_x = ReadCoord(); + self.size_y = ReadCoord(); + self.size_z = ReadCoord(); + self.wait = ReadByte(); + + self.classname = "door"; + self.movetype = MOVETYPE_PUSH; + self.solid = SOLID_TRIGGER; + self.draw = door_draw; + self.drawmask = MASK_NORMAL; + self.move_time = time; +} + +#endif diff --git a/qcsrc/common/triggers/f_door.qh b/qcsrc/common/triggers/f_door.qh index 21046b1fe..cc508e8d9 100644 --- a/qcsrc/common/triggers/f_door.qh +++ b/qcsrc/common/triggers/f_door.qh @@ -3,8 +3,16 @@ const float DOOR_START_OPEN = 1; const float DOOR_DONT_LINK = 4; const float DOOR_TOGGLE = 32; +const float DOOR_NOSPLASH = 256; // generic anti-splashdamage spawnflag + const float SPAWNFLAGS_GOLD_KEY = 8; const float SPAWNFLAGS_SILVER_KEY = 16; -// door properties -.entity trigger_field; +#ifdef CSQC +// stuff for preload +void ent_door(); +void ent_door_trigger(); + +// abused +.float attack_finished_single; +#endif diff --git a/qcsrc/common/triggers/include.qc b/qcsrc/common/triggers/include.qc index a5b279ec4..8a0060915 100644 --- a/qcsrc/common/triggers/include.qc +++ b/qcsrc/common/triggers/include.qc @@ -1 +1,3 @@ +#include "subs.qc" +#include "triggers.qc" #include "f_door.qc" diff --git a/qcsrc/common/triggers/include.qh b/qcsrc/common/triggers/include.qh index ecdddbd1c..d819fcead 100644 --- a/qcsrc/common/triggers/include.qh +++ b/qcsrc/common/triggers/include.qh @@ -1 +1,7 @@ +#ifdef CSQC +#include "../../server/item_key.qh" +#endif #include "f_door.qh" +#include "triggers.qh" +#include "subs.qh" +#include "triggers.qh" diff --git a/qcsrc/server/constants.qh b/qcsrc/server/constants.qh index ada2acd1a..e9d944c44 100644 --- a/qcsrc/server/constants.qh +++ b/qcsrc/server/constants.qh @@ -19,5 +19,3 @@ const float MSG_ENTITY = 5; // csqc const float NUM_PLAYERSKINS_TEAMPLAY = 3; const float ASSAULT_VALUE_INACTIVE = 1000; - -const float DOOR_NOSPLASH = 256; // generic anti-splashdamage spawnflag diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 870c61c75..752bc99cd 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -41,8 +41,6 @@ float g_jetpack; float sv_clones; float sv_foginterval; -entity activator; - float player_count; float currentbots; float bots_would_leave; @@ -65,21 +63,6 @@ float server_is_dedicated; //.string map; //.float worldtype; -.float delay; -.float wait; -.float lip; -//.float light_lev; -.float speed; -//.float style; -//.float skill; -.float sounds; -.string platmovetype; -.float platmovetype_start, platmovetype_end; - -.string killtarget; - -.vector pos1, pos2; -.vector mangle; .float pain_finished; //Added by Supajoe .float pain_frame; //" @@ -89,14 +72,7 @@ float server_is_dedicated; .float invincible_finished; .float superweapons_finished; -.vector finaldest, finalangle; //plat.qc stuff -.void() think1; -.float state; -.float t_length, t_width; - -.vector destvec; // for rain -.vector destvec2; // for train -.float cnt; // for rain +.float cnt; // used in too many places .float count; //.float cnt2; @@ -108,15 +84,6 @@ float server_is_dedicated; .float fade_time; .float fade_rate; -// player animation state -.float animstate_startframe; -.float animstate_numframes; -.float animstate_framerate; -.float animstate_starttime; -.float animstate_endtime; -.float animstate_override; -.float animstate_looping; - // weapon animation vectors: .vector anim_fire1; .vector anim_fire2; @@ -205,20 +172,11 @@ const float WS_READY = 4; // idle frame void weapon_defaultspawnfunc(float wpn); -.vector dest1, dest2; - float gameover; float intermission_running; float intermission_exittime; float alreadychangedlevel; -// Keys player is holding -.float itemkeys; -// message delay for func_door locked by keys and key locks -// this field is used on player entities -.float key_door_messagetime; - - .float version; //swamp @@ -454,16 +412,6 @@ void W_Porto_Remove (entity p); // may be useful to all weapons .float bulletcounter; -void target_voicescript_next(entity pl); -void target_voicescript_clear(entity pl); - -.string target2; -.string target3; -.string target4; -.string curvetarget; -.float target_random; -.float trigger_reverse; - // Nexball .entity ballcarried; // Also used for keepaway .float metertime; diff --git a/qcsrc/server/g_subs.qc b/qcsrc/server/g_subs.qc index fd0dc7861..871a20bbd 100644 --- a/qcsrc/server/g_subs.qc +++ b/qcsrc/server/g_subs.qc @@ -1,10 +1,3 @@ -void SUB_NullThink(void) { } - -void() SUB_CalcMoveDone; -void() SUB_CalcAngleMoveDone; -//void() SUB_UseTargets; -void() SUB_Remove; - void spawnfunc_info_null (void) { remove(self); @@ -55,387 +48,6 @@ void updateanim(entity e) //print(ftos(time), " -> ", ftos(e.frame), "\n"); } -/* -================== -SUB_Remove - -Remove self -================== -*/ -void SUB_Remove (void) -{ - remove (self); -} - -/* -================== -SUB_Friction - -Applies some friction to self -================== -*/ -.float friction; -void SUB_Friction (void) -{ - self.nextthink = time; - if(self.flags & FL_ONGROUND) - self.velocity = self.velocity * (1 - frametime * self.friction); -} - -/* -================== -SUB_VanishOrRemove - -Makes client invisible or removes non-client -================== -*/ -void SUB_VanishOrRemove (entity ent) -{ - if (IS_CLIENT(ent)) - { - // vanish - ent.alpha = -1; - ent.effects = 0; - ent.glow_size = 0; - ent.pflags = 0; - } - else - { - // remove - remove (ent); - } -} - -void SUB_SetFade_Think (void) -{ - if(self.alpha == 0) - self.alpha = 1; - self.think = SUB_SetFade_Think; - self.nextthink = time; - self.alpha -= frametime * self.fade_rate; - if (self.alpha < 0.01) - SUB_VanishOrRemove(self); - else - self.nextthink = time; -} - -/* -================== -SUB_SetFade - -Fade 'ent' out when time >= 'when' -================== -*/ -void SUB_SetFade (entity ent, float when, float fadetime) -{ - ent.fade_rate = 1/fadetime; - ent.think = SUB_SetFade_Think; - ent.nextthink = when; -} - -/* -============= -SUB_CalcMove - -calculate self.velocity and self.nextthink to reach dest from -self.origin traveling at speed -=============== -*/ -void SUB_CalcMoveDone (void) -{ - // After moving, set origin to exact final destination - - setorigin (self, self.finaldest); - self.velocity = '0 0 0'; - self.nextthink = -1; - if (self.think1) - self.think1 (); -} - -.float platmovetype_turn; -void SUB_CalcMove_controller_think (void) -{ - entity oldself; - float traveltime; - float phasepos; - float nexttick; - vector delta; - vector delta2; - vector veloc; - vector angloc; - vector nextpos; - delta = self.destvec; - delta2 = self.destvec2; - if(time < self.animstate_endtime) { - nexttick = time + sys_frametime; - - traveltime = self.animstate_endtime - self.animstate_starttime; - phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1] - phasepos = cubic_speedfunc(self.platmovetype_start, self.platmovetype_end, phasepos); - nextpos = self.origin + (delta * phasepos) + (delta2 * phasepos * phasepos); - // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning) - - if(self.owner.platmovetype_turn) - { - vector destangle; - destangle = delta + 2 * delta2 * phasepos; - destangle = vectoangles(destangle); - destangle_x = -destangle_x; // flip up / down orientation - - // take the shortest distance for the angles - self.owner.angles_x -= 360 * floor((self.owner.angles_x - destangle_x) / 360 + 0.5); - self.owner.angles_y -= 360 * floor((self.owner.angles_y - destangle_y) / 360 + 0.5); - self.owner.angles_z -= 360 * floor((self.owner.angles_z - destangle_z) / 360 + 0.5); - angloc = destangle - self.owner.angles; - angloc = angloc * (1 / sys_frametime); // so it arrives for the next frame - self.owner.avelocity = angloc; - } - if(nexttick < self.animstate_endtime) - veloc = nextpos - self.owner.origin; - else - veloc = self.finaldest - self.owner.origin; - veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame - - self.owner.velocity = veloc; - self.nextthink = nexttick; - } else { - // derivative: delta + 2 * delta2 (e.g. for angle positioning) - oldself = self; - self.owner.think = self.think1; - self = self.owner; - remove(oldself); - self.think(); - } -} - -void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector dest) -{ - // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + dest * t * t - // 2 * control * t - 2 * control * t * t + dest * t * t - // 2 * control * t + (dest - 2 * control) * t * t - - controller.origin = org; // starting point - control -= org; - dest -= org; - - controller.destvec = 2 * control; // control point - controller.destvec2 = dest - 2 * control; // quadratic part required to reach end point - // also: initial d/dphasepos origin = 2 * control, final speed = 2 * (dest - control) -} - -void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector dest) -{ - // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + dest * t * t - // 2 * control * t - 2 * control * t * t + dest * t * t - // 2 * control * t + (dest - 2 * control) * t * t - - controller.origin = org; // starting point - dest -= org; - - controller.destvec = dest; // end point - controller.destvec2 = '0 0 0'; -} - -float TSPEED_TIME = -1; -float TSPEED_LINEAR = 0; -float TSPEED_START = 1; -float TSPEED_END = 2; -// TODO average too? - -void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeedtype, float tspeed, void() func) -{ - float traveltime; - entity controller; - - if (!tspeed) - objerror ("No speed is defined!"); - - self.think1 = func; - self.finaldest = tdest; - self.think = SUB_CalcMoveDone; - - switch(tspeedtype) - { - default: - case TSPEED_START: - traveltime = 2 * vlen(tcontrol - self.origin) / tspeed; - break; - case TSPEED_END: - traveltime = 2 * vlen(tcontrol - tdest) / tspeed; - break; - case TSPEED_LINEAR: - traveltime = vlen(tdest - self.origin) / tspeed; - break; - case TSPEED_TIME: - traveltime = tspeed; - break; - } - - if (traveltime < 0.1) // useless anim - { - self.velocity = '0 0 0'; - self.nextthink = self.ltime + 0.1; - return; - } - - controller = spawn(); - controller.classname = "SUB_CalcMove_controller"; - controller.owner = self; - controller.platmovetype = self.platmovetype; - controller.platmovetype_start = self.platmovetype_start; - controller.platmovetype_end = self.platmovetype_end; - SUB_CalcMove_controller_setbezier(controller, self.origin, tcontrol, tdest); - controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit. - controller.animstate_starttime = time; - controller.animstate_endtime = time + traveltime; - controller.think = SUB_CalcMove_controller_think; - controller.think1 = self.think; - - // the thinking is now done by the controller - self.think = SUB_NullThink; // for PushMove - self.nextthink = self.ltime + traveltime; - - // invoke controller - self = controller; - self.think(); - self = self.owner; -} - -void SUB_CalcMove (vector tdest, float tspeedtype, float tspeed, void() func) -{ - vector delta; - float traveltime; - - if (!tspeed) - objerror ("No speed is defined!"); - - self.think1 = func; - self.finaldest = tdest; - self.think = SUB_CalcMoveDone; - - if (tdest == self.origin) - { - self.velocity = '0 0 0'; - self.nextthink = self.ltime + 0.1; - return; - } - - delta = tdest - self.origin; - - switch(tspeedtype) - { - default: - case TSPEED_START: - case TSPEED_END: - case TSPEED_LINEAR: - traveltime = vlen (delta) / tspeed; - break; - case TSPEED_TIME: - traveltime = tspeed; - break; - } - - // Very short animations don't really show off the effect - // of controlled animation, so let's just use linear movement. - // Alternatively entities can choose to specify non-controlled movement. - // The only currently implemented alternative movement is linear (value 1) - if (traveltime < 0.15 || (self.platmovetype_start == 1 && self.platmovetype_end == 1)) // is this correct? - { - self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division - self.nextthink = self.ltime + traveltime; - return; - } - - // now just run like a bezier curve... - SUB_CalcMove_Bezier((self.origin + tdest) * 0.5, tdest, tspeedtype, tspeed, func); -} - -void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void() func) -{ - entity oldself; - - oldself = self; - self = ent; - - SUB_CalcMove (tdest, tspeedtype, tspeed, func); - - self = oldself; -} - -/* -============= -SUB_CalcAngleMove - -calculate self.avelocity and self.nextthink to reach destangle from -self.angles rotating - -The calling function should make sure self.think is valid -=============== -*/ -void SUB_CalcAngleMoveDone (void) -{ - // After rotating, set angle to exact final angle - self.angles = self.finalangle; - self.avelocity = '0 0 0'; - self.nextthink = -1; - if (self.think1) - self.think1 (); -} - -// FIXME: I fixed this function only for rotation around the main axes -void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func) -{ - vector delta; - float traveltime; - - if (!tspeed) - objerror ("No speed is defined!"); - - // take the shortest distance for the angles - self.angles_x -= 360 * floor((self.angles_x - destangle_x) / 360 + 0.5); - self.angles_y -= 360 * floor((self.angles_y - destangle_y) / 360 + 0.5); - self.angles_z -= 360 * floor((self.angles_z - destangle_z) / 360 + 0.5); - delta = destangle - self.angles; - - switch(tspeedtype) - { - default: - case TSPEED_START: - case TSPEED_END: - case TSPEED_LINEAR: - traveltime = vlen (delta) / tspeed; - break; - case TSPEED_TIME: - traveltime = tspeed; - break; - } - - self.think1 = func; - self.finalangle = destangle; - self.think = SUB_CalcAngleMoveDone; - - if (traveltime < 0.1) - { - self.avelocity = '0 0 0'; - self.nextthink = self.ltime + 0.1; - return; - } - - self.avelocity = delta * (1 / traveltime); - self.nextthink = self.ltime + traveltime; -} - -void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void() func) -{ - entity oldself; - - oldself = self; - self = ent; - - SUB_CalcAngleMove (destangle, tspeedtype, tspeed, func); - - self = oldself; -} /* ================== diff --git a/qcsrc/server/g_triggers.qc b/qcsrc/server/g_triggers.qc deleted file mode 100644 index c5fb08c96..000000000 --- a/qcsrc/server/g_triggers.qc +++ /dev/null @@ -1,2159 +0,0 @@ -void SUB_DontUseTargets() -{ -} - - -void() SUB_UseTargets; - -void DelayThink() -{ - activator = self.enemy; - SUB_UseTargets (); - remove(self); -} - -/* -============================== -SUB_UseTargets - -the global "activator" should be set to the entity that initiated the firing. - -If self.delay is set, a DelayedUse entity will be created that will actually -do the SUB_UseTargets after that many seconds have passed. - -Centerprints any self.message to the activator. - -Removes all entities with a targetname that match self.killtarget, -and removes them, so some events can remove other triggers. - -Search for (string)targetname in all entities that -match (string)self.target and call their .use function - -============================== -*/ -void SUB_UseTargets() -{ - entity t, stemp, otemp, act; - string s; - float i; - -// -// check for a delay -// - if (self.delay) - { - // create a temp object to fire at a later time - t = spawn(); - t.classname = "DelayedUse"; - t.nextthink = time + self.delay; - t.think = DelayThink; - t.enemy = activator; - t.message = self.message; - t.killtarget = self.killtarget; - t.target = self.target; - t.target2 = self.target2; - t.target3 = self.target3; - t.target4 = self.target4; - return; - } - - -// -// print the message -// - if(self) - if(IS_PLAYER(activator) && self.message != "") - if(IS_REAL_CLIENT(activator)) - { - centerprint(activator, self.message); - if (self.noise == "") - play2(activator, "misc/talk.wav"); - } - -// -// kill the killtagets -// - s = self.killtarget; - if (s != "") - { - for(t = world; (t = find(t, targetname, s)); ) - remove(t); - } - -// -// fire targets -// - act = activator; - stemp = self; - otemp = other; - - if(stemp.target_random) - RandomSelection_Init(); - - for(i = 0; i < 4; ++i) - { - switch(i) - { - default: - case 0: s = stemp.target; break; - case 1: s = stemp.target2; break; - case 2: s = stemp.target3; break; - case 3: s = stemp.target4; break; - } - if (s != "") - { - for(t = world; (t = find(t, targetname, s)); ) - if(t.use) - { - if(stemp.target_random) - { - RandomSelection_Add(t, 0, string_null, 1, 0); - } - else - { - self = t; - other = stemp; - activator = act; - self.use(); - } - } - } - } - - if(stemp.target_random && RandomSelection_chosen_ent) - { - self = RandomSelection_chosen_ent; - other = stemp; - activator = act; - self.use(); - } - - activator = act; - self = stemp; - other = otemp; -} - - -//============================================================================= - -const float SPAWNFLAG_NOMESSAGE = 1; -const float SPAWNFLAG_NOTOUCH = 1; - -// the wait time has passed, so set back up for another activation -void multi_wait() -{ - if (self.max_health) - { - self.health = self.max_health; - self.takedamage = DAMAGE_YES; - self.solid = SOLID_BBOX; - } -} - - -// the trigger was just touched/killed/used -// self.enemy should be set to the activator so it can be held through a delay -// so wait for the delay time before firing -void multi_trigger() -{ - if (self.nextthink > time) - { - return; // allready been triggered - } - - if (self.classname == "trigger_secret") - { - if (!IS_PLAYER(self.enemy)) - return; - found_secrets = found_secrets + 1; - WriteByte (MSG_ALL, SVC_FOUNDSECRET); - } - - if (self.noise) - sound (self.enemy, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM); - -// don't trigger again until reset - self.takedamage = DAMAGE_NO; - - activator = self.enemy; - other = self.goalentity; - SUB_UseTargets(); - - if (self.wait > 0) - { - self.think = multi_wait; - self.nextthink = time + self.wait; - } - else if (self.wait == 0) - { - multi_wait(); // waiting finished - } - else - { // we can't just remove (self) here, because this is a touch function - // called wheil C code is looping through area links... - self.touch = func_null; - } -} - -void multi_use() -{ - self.goalentity = other; - self.enemy = activator; - multi_trigger(); -} - -void multi_touch() -{ - if(!(self.spawnflags & 2)) - if(!other.iscreature) - return; - - if(self.team) - if(((self.spawnflags & 4) == 0) == (self.team != other.team)) - return; - -// if the trigger has an angles field, check player's facing direction - if (self.movedir != '0 0 0') - { - makevectors (other.angles); - if (v_forward * self.movedir < 0) - return; // not facing the right way - } - - EXACTTRIGGER_TOUCH; - - self.enemy = other; - self.goalentity = other; - multi_trigger (); -} - -void multi_eventdamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) -{ - if (!self.takedamage) - return; - if(self.spawnflags & DOOR_NOSPLASH) - if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH)) - return; - self.health = self.health - damage; - if (self.health <= 0) - { - self.enemy = attacker; - self.goalentity = inflictor; - multi_trigger(); - } -} - -void multi_reset() -{ - if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) ) - self.touch = multi_touch; - if (self.max_health) - { - self.health = self.max_health; - self.takedamage = DAMAGE_YES; - self.solid = SOLID_BBOX; - } - self.think = func_null; - self.nextthink = 0; - self.team = self.team_saved; -} - -/*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch -Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time. -If "delay" is set, the trigger waits some time after activating before firing. -"wait" : Seconds between triggerings. (.2 default) -If notouch is set, the trigger is only fired by other entities, not by touching. -NOTOUCH has been obsoleted by spawnfunc_trigger_relay! -sounds -1) secret -2) beep beep -3) large switch -4) -set "message" to text string -*/ -void spawnfunc_trigger_multiple() -{ - self.reset = multi_reset; - if (self.sounds == 1) - { - precache_sound ("misc/secret.wav"); - self.noise = "misc/secret.wav"; - } - else if (self.sounds == 2) - { - precache_sound ("misc/talk.wav"); - self.noise = "misc/talk.wav"; - } - else if (self.sounds == 3) - { - precache_sound ("misc/trigger1.wav"); - self.noise = "misc/trigger1.wav"; - } - - if (!self.wait) - self.wait = 0.2; - else if(self.wait < -1) - self.wait = 0; - self.use = multi_use; - - EXACTTRIGGER_INIT; - - self.team_saved = self.team; - - if (self.health) - { - if (self.spawnflags & SPAWNFLAG_NOTOUCH) - objerror ("health and notouch don't make sense\n"); - self.max_health = self.health; - self.event_damage = multi_eventdamage; - self.takedamage = DAMAGE_YES; - self.solid = SOLID_BBOX; - setorigin (self, self.origin); // make sure it links into the world - } - else - { - if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) ) - { - self.touch = multi_touch; - setorigin (self, self.origin); // make sure it links into the world - } - } -} - - -/*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch -Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching -"targetname". If "health" is set, the trigger must be killed to activate. -If notouch is set, the trigger is only fired by other entities, not by touching. -if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired. -if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0. -sounds -1) secret -2) beep beep -3) large switch -4) -set "message" to text string -*/ -void spawnfunc_trigger_once() -{ - self.wait = -1; - spawnfunc_trigger_multiple(); -} - -//============================================================================= - -/*QUAKED spawnfunc_trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) -This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages. -*/ -void spawnfunc_trigger_relay() -{ - self.use = SUB_UseTargets; - self.reset = spawnfunc_trigger_relay; // this spawnfunc resets fully -} - -void delay_use() -{ - self.think = SUB_UseTargets; - self.nextthink = self.wait; -} - -void delay_reset() -{ - self.think = func_null; - self.nextthink = 0; -} - -void spawnfunc_trigger_delay() -{ - if(!self.wait) - self.wait = 1; - - self.use = delay_use; - self.reset = delay_reset; -} - -//============================================================================= - - -void counter_use() -{ - self.count -= 1; - if (self.count < 0) - return; - - if (self.count == 0) - { - if(IS_PLAYER(activator) && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0) - Send_Notification(NOTIF_ONE, activator, MSG_CENTER, CENTER_SEQUENCE_COMPLETED); - - self.enemy = activator; - multi_trigger (); - } - else - { - if(IS_PLAYER(activator) && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0) - if(self.count >= 4) - Send_Notification(NOTIF_ONE, activator, MSG_CENTER, CENTER_SEQUENCE_COUNTER); - else - Send_Notification(NOTIF_ONE, activator, MSG_CENTER, CENTER_SEQUENCE_COUNTER_FEWMORE, self.count); - } -} - -void counter_reset() -{ - self.count = self.cnt; - multi_reset(); -} - -/*QUAKED spawnfunc_trigger_counter (.5 .5 .5) ? nomessage -Acts as an intermediary for an action that takes multiple inputs. - -If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished. - -After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself. -*/ -void spawnfunc_trigger_counter() -{ - self.wait = -1; - if (!self.count) - self.count = 2; - self.cnt = self.count; - - self.use = counter_use; - self.reset = counter_reset; -} - -void trigger_hurt_use() -{ - if(IS_PLAYER(activator)) - self.enemy = activator; - else - self.enemy = world; // let's just destroy it, if taking over is too much work -} - -.float triggerhurttime; -void trigger_hurt_touch() -{ - if (self.active != ACTIVE_ACTIVE) - return; - - if(self.team) - if(((self.spawnflags & 4) == 0) == (self.team != other.team)) - return; - - // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu) - if (other.iscreature) - { - if (other.takedamage) - if (other.triggerhurttime < time) - { - EXACTTRIGGER_TOUCH; - other.triggerhurttime = time + 1; - - entity own; - own = self.enemy; - if (!IS_PLAYER(own)) - { - own = self; - self.enemy = world; // I still hate you all - } - - Damage (other, self, own, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0'); - } - } - else if(other.damagedbytriggers) - { - if(other.takedamage) - { - EXACTTRIGGER_TOUCH; - Damage(other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0'); - } - } - - return; -} - -/*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ? -Any object touching this will be hurt -set dmg to damage amount -defalt dmg = 5 -*/ -.entity trigger_hurt_next; -entity trigger_hurt_last; -entity trigger_hurt_first; -void spawnfunc_trigger_hurt() -{ - EXACTTRIGGER_INIT; - self.active = ACTIVE_ACTIVE; - self.touch = trigger_hurt_touch; - self.use = trigger_hurt_use; - self.enemy = world; // I hate you all - if (!self.dmg) - self.dmg = 1000; - if (self.message == "") - self.message = "was in the wrong place"; - if (self.message2 == "") - self.message2 = "was thrown into a world of hurt by"; - // self.message = "someone like %s always gets wrongplaced"; - - if(!trigger_hurt_first) - trigger_hurt_first = self; - if(trigger_hurt_last) - trigger_hurt_last.trigger_hurt_next = self; - trigger_hurt_last = self; -} - -float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end) -{ - entity th; - - for(th = trigger_hurt_first; th; th = th.trigger_hurt_next) - if(tracebox_hits_box(start, mi, ma, end, th.absmin, th.absmax)) - return TRUE; - - return FALSE; -} - -////////////////////////////////////////////////////////////// -// -// -// -//Trigger heal --a04191b92fbd93aa67214ef7e72d6d2e -// -////////////////////////////////////////////////////////////// - -.float triggerhealtime; -void trigger_heal_touch() -{ - if (self.active != ACTIVE_ACTIVE) - return; - - // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu) - if (other.iscreature) - { - if (other.takedamage) - if (!other.deadflag) - if (other.triggerhealtime < time) - { - EXACTTRIGGER_TOUCH; - other.triggerhealtime = time + 1; - - if (other.health < self.max_health) - { - other.health = min(other.health + self.health, self.max_health); - other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot); - sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM); - } - } - } -} - -void spawnfunc_trigger_heal() -{ - self.active = ACTIVE_ACTIVE; - - EXACTTRIGGER_INIT; - self.touch = trigger_heal_touch; - if (!self.health) - self.health = 10; - if (!self.max_health) - self.max_health = 200; //Max health topoff for field - if(self.noise == "") - self.noise = "misc/mediumhealth.wav"; - precache_sound(self.noise); -} - - -////////////////////////////////////////////////////////////// -// -// -// -//End trigger_heal -// -////////////////////////////////////////////////////////////// - -.entity trigger_gravity_check; -void trigger_gravity_remove(entity own) -{ - if(own.trigger_gravity_check.owner == own) - { - UpdateCSQCProjectile(own); - own.gravity = own.trigger_gravity_check.gravity; - remove(own.trigger_gravity_check); - } - else - backtrace("Removing a trigger_gravity_check with no valid owner"); - own.trigger_gravity_check = world; -} -void trigger_gravity_check_think() -{ - // This spawns when a player enters the gravity zone and checks if he left. - // Each frame, self.count is set to 2 by trigger_gravity_touch() and decreased by 1 here. - // It the player has left the gravity trigger, this will be allowed to reach 0 and indicate that. - if(self.count <= 0) - { - if(self.owner.trigger_gravity_check == self) - trigger_gravity_remove(self.owner); - else - remove(self); - return; - } - else - { - self.count -= 1; - self.nextthink = time; - } -} - -void trigger_gravity_use() -{ - self.state = !self.state; -} - -void trigger_gravity_touch() -{ - float g; - - if(self.state != TRUE) - return; - - EXACTTRIGGER_TOUCH; - - g = self.gravity; - - if (!(self.spawnflags & 1)) - { - if(other.trigger_gravity_check) - { - if(self == other.trigger_gravity_check.enemy) - { - // same? - other.trigger_gravity_check.count = 2; // gravity one more frame... - return; - } - - // compare prio - if(self.cnt > other.trigger_gravity_check.enemy.cnt) - trigger_gravity_remove(other); - else - return; - } - other.trigger_gravity_check = spawn(); - other.trigger_gravity_check.enemy = self; - other.trigger_gravity_check.owner = other; - other.trigger_gravity_check.gravity = other.gravity; - other.trigger_gravity_check.think = trigger_gravity_check_think; - other.trigger_gravity_check.nextthink = time; - other.trigger_gravity_check.count = 2; - if(other.gravity) - g *= other.gravity; - } - - if (other.gravity != g) - { - other.gravity = g; - if(self.noise != "") - sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM); - UpdateCSQCProjectile(self.owner); - } -} - -void spawnfunc_trigger_gravity() -{ - if(self.gravity == 1) - return; - - EXACTTRIGGER_INIT; - self.touch = trigger_gravity_touch; - if(self.noise != "") - precache_sound(self.noise); - - self.state = TRUE; - IFTARGETED - { - self.use = trigger_gravity_use; - if(self.spawnflags & 2) - self.state = FALSE; - } -} - -//============================================================================= - -// TODO add a way to do looped sounds with sound(); then complete this entity -.float volume, atten; -void target_speaker_use_off(); -void target_speaker_use_activator() -{ - if (!IS_REAL_CLIENT(activator)) - return; - string snd; - if(substring(self.noise, 0, 1) == "*") - { - var .string sample; - sample = GetVoiceMessageSampleField(substring(self.noise, 1, -1)); - if(GetPlayerSoundSampleField_notFound) - snd = "misc/null.wav"; - else if(activator.sample == "") - snd = "misc/null.wav"; - else - { - tokenize_console(activator.sample); - float n; - n = stof(argv(1)); - if(n > 0) - snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization - else - snd = strcat(argv(0), ".wav"); // randomization - } - } - else - snd = self.noise; - msg_entity = activator; - soundto(MSG_ONE, self, CH_TRIGGER, snd, VOL_BASE * self.volume, self.atten); -} -void target_speaker_use_on() -{ - string snd; - if(substring(self.noise, 0, 1) == "*") - { - var .string sample; - sample = GetVoiceMessageSampleField(substring(self.noise, 1, -1)); - if(GetPlayerSoundSampleField_notFound) - snd = "misc/null.wav"; - else if(activator.sample == "") - snd = "misc/null.wav"; - else - { - tokenize_console(activator.sample); - float n; - n = stof(argv(1)); - if(n > 0) - snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization - else - snd = strcat(argv(0), ".wav"); // randomization - } - } - else - snd = self.noise; - sound(self, CH_TRIGGER_SINGLE, snd, VOL_BASE * self.volume, self.atten); - if(self.spawnflags & 3) - self.use = target_speaker_use_off; -} -void target_speaker_use_off() -{ - sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASE * self.volume, self.atten); - self.use = target_speaker_use_on; -} -void target_speaker_reset() -{ - if(self.spawnflags & 1) // LOOPED_ON - { - if(self.use == target_speaker_use_on) - target_speaker_use_on(); - } - else if(self.spawnflags & 2) - { - if(self.use == target_speaker_use_off) - target_speaker_use_off(); - } -} - -void spawnfunc_target_speaker() -{ - // TODO: "*" prefix to sound file name - // TODO: wait and random (just, HOW? random is not a field) - if(self.noise) - precache_sound (self.noise); - - if(!self.atten && !(self.spawnflags & 4)) - { - IFTARGETED - self.atten = ATTEN_NORM; - else - self.atten = ATTEN_STATIC; - } - else if(self.atten < 0) - self.atten = 0; - - if(!self.volume) - self.volume = 1; - - IFTARGETED - { - if(self.spawnflags & 8) // ACTIVATOR - self.use = target_speaker_use_activator; - else if(self.spawnflags & 1) // LOOPED_ON - { - target_speaker_use_on(); - self.reset = target_speaker_reset; - } - else if(self.spawnflags & 2) // LOOPED_OFF - { - self.use = target_speaker_use_on; - self.reset = target_speaker_reset; - } - else - self.use = target_speaker_use_on; - } - else if(self.spawnflags & 1) // LOOPED_ON - { - ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten); - remove(self); - } - else if(self.spawnflags & 2) // LOOPED_OFF - { - objerror("This sound entity can never be activated"); - } - else - { - // Quake/Nexuiz fallback - ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten); - remove(self); - } -} - - -void spawnfunc_func_stardust() { - self.effects = EF_STARDUST; -} - -.string bgmscript; -.float bgmscriptattack; -.float bgmscriptdecay; -.float bgmscriptsustain; -.float bgmscriptrelease; -float pointparticles_SendEntity(entity to, float fl) -{ - WriteByte(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES); - - // optional features to save space - fl = fl & 0x0F; - if(self.spawnflags & 2) - fl |= 0x10; // absolute count on toggle-on - if(self.movedir != '0 0 0' || self.velocity != '0 0 0') - fl |= 0x20; // 4 bytes - saves CPU - if(self.waterlevel || self.count != 1) - fl |= 0x40; // 4 bytes - obscure features almost never used - if(self.mins != '0 0 0' || self.maxs != '0 0 0') - fl |= 0x80; // 14 bytes - saves lots of space - - WriteByte(MSG_ENTITY, fl); - if(fl & 2) - { - if(self.state) - WriteCoord(MSG_ENTITY, self.impulse); - else - WriteCoord(MSG_ENTITY, 0); // off - } - if(fl & 4) - { - WriteCoord(MSG_ENTITY, self.origin_x); - WriteCoord(MSG_ENTITY, self.origin_y); - WriteCoord(MSG_ENTITY, self.origin_z); - } - if(fl & 1) - { - if(self.model != "null") - { - WriteShort(MSG_ENTITY, self.modelindex); - if(fl & 0x80) - { - WriteCoord(MSG_ENTITY, self.mins_x); - WriteCoord(MSG_ENTITY, self.mins_y); - WriteCoord(MSG_ENTITY, self.mins_z); - WriteCoord(MSG_ENTITY, self.maxs_x); - WriteCoord(MSG_ENTITY, self.maxs_y); - WriteCoord(MSG_ENTITY, self.maxs_z); - } - } - else - { - WriteShort(MSG_ENTITY, 0); - if(fl & 0x80) - { - WriteCoord(MSG_ENTITY, self.maxs_x); - WriteCoord(MSG_ENTITY, self.maxs_y); - WriteCoord(MSG_ENTITY, self.maxs_z); - } - } - WriteShort(MSG_ENTITY, self.cnt); - if(fl & 0x20) - { - WriteShort(MSG_ENTITY, compressShortVector(self.velocity)); - WriteShort(MSG_ENTITY, compressShortVector(self.movedir)); - } - if(fl & 0x40) - { - WriteShort(MSG_ENTITY, self.waterlevel * 16.0); - WriteByte(MSG_ENTITY, self.count * 16.0); - } - WriteString(MSG_ENTITY, self.noise); - if(self.noise != "") - { - WriteByte(MSG_ENTITY, floor(self.atten * 64)); - WriteByte(MSG_ENTITY, floor(self.volume * 255)); - } - WriteString(MSG_ENTITY, self.bgmscript); - if(self.bgmscript != "") - { - WriteByte(MSG_ENTITY, floor(self.bgmscriptattack * 64)); - WriteByte(MSG_ENTITY, floor(self.bgmscriptdecay * 64)); - WriteByte(MSG_ENTITY, floor(self.bgmscriptsustain * 255)); - WriteByte(MSG_ENTITY, floor(self.bgmscriptrelease * 64)); - } - } - return 1; -} - -void pointparticles_use() -{ - self.state = !self.state; - self.SendFlags |= 2; -} - -void pointparticles_think() -{ - if(self.origin != self.oldorigin) - { - self.SendFlags |= 4; - self.oldorigin = self.origin; - } - self.nextthink = time; -} - -void pointparticles_reset() -{ - if(self.spawnflags & 1) - self.state = 1; - else - self.state = 0; -} - -void spawnfunc_func_pointparticles() -{ - if(self.model != "") - setmodel(self, self.model); - if(self.noise != "") - precache_sound (self.noise); - - if(!self.bgmscriptsustain) - self.bgmscriptsustain = 1; - else if(self.bgmscriptsustain < 0) - self.bgmscriptsustain = 0; - - if(!self.atten) - self.atten = ATTEN_NORM; - else if(self.atten < 0) - self.atten = 0; - if(!self.volume) - self.volume = 1; - if(!self.count) - self.count = 1; - if(!self.impulse) - self.impulse = 1; - - if(!self.modelindex) - { - setorigin(self, self.origin + self.mins); - setsize(self, '0 0 0', self.maxs - self.mins); - } - if(!self.cnt) - self.cnt = particleeffectnum(self.mdl); - - Net_LinkEntity(self, (self.spawnflags & 4), 0, pointparticles_SendEntity); - - IFTARGETED - { - self.use = pointparticles_use; - self.reset = pointparticles_reset; - self.reset(); - } - else - self.state = 1; - self.think = pointparticles_think; - self.nextthink = time; -} - -void spawnfunc_func_sparks() -{ - // self.cnt is the amount of sparks that one burst will spawn - if(self.cnt < 1) { - self.cnt = 25.0; // nice default value - } - - // self.wait is the probability that a sparkthink will spawn a spark shower - // range: 0 - 1, but 0 makes little sense, so... - if(self.wait < 0.05) { - self.wait = 0.25; // nice default value - } - - self.count = self.cnt; - self.mins = '0 0 0'; - self.maxs = '0 0 0'; - self.velocity = '0 0 -1'; - self.mdl = "TE_SPARK"; - self.impulse = 10 * self.wait; // by default 2.5/sec - self.wait = 0; - self.cnt = 0; // use mdl - - spawnfunc_func_pointparticles(); -} - -float rainsnow_SendEntity(entity to, float sf) -{ - WriteByte(MSG_ENTITY, ENT_CLIENT_RAINSNOW); - WriteByte(MSG_ENTITY, self.state); - WriteCoord(MSG_ENTITY, self.origin_x + self.mins_x); - WriteCoord(MSG_ENTITY, self.origin_y + self.mins_y); - WriteCoord(MSG_ENTITY, self.origin_z + self.mins_z); - WriteCoord(MSG_ENTITY, self.maxs_x - self.mins_x); - WriteCoord(MSG_ENTITY, self.maxs_y - self.mins_y); - WriteCoord(MSG_ENTITY, self.maxs_z - self.mins_z); - WriteShort(MSG_ENTITY, compressShortVector(self.dest)); - WriteShort(MSG_ENTITY, self.count); - WriteByte(MSG_ENTITY, self.cnt); - return 1; -} - -/*QUAKED spawnfunc_func_rain (0 .5 .8) ? -This is an invisible area like a trigger, which rain falls inside of. - -Keys: -"velocity" - falling direction (should be something like '0 0 -700', use the X and Y velocity for wind) -"cnt" - sets color of rain (default 12 - white) -"count" - adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000 -*/ -void spawnfunc_func_rain() -{ - self.dest = self.velocity; - self.velocity = '0 0 0'; - if (!self.dest) - self.dest = '0 0 -700'; - self.angles = '0 0 0'; - self.movetype = MOVETYPE_NONE; - self.solid = SOLID_NOT; - SetBrushEntityModel(); - if (!self.cnt) - self.cnt = 12; - if (!self.count) - self.count = 2000; - self.count = 0.01 * self.count * (self.size_x / 1024) * (self.size_y / 1024); - if (self.count < 1) - self.count = 1; - if(self.count > 65535) - self.count = 65535; - - self.state = 1; // 1 is rain, 0 is snow - self.Version = 1; - - Net_LinkEntity(self, FALSE, 0, rainsnow_SendEntity); -} - - -/*QUAKED spawnfunc_func_snow (0 .5 .8) ? -This is an invisible area like a trigger, which snow falls inside of. - -Keys: -"velocity" - falling direction (should be something like '0 0 -300', use the X and Y velocity for wind) -"cnt" - sets color of rain (default 12 - white) -"count" - adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000 -*/ -void spawnfunc_func_snow() -{ - self.dest = self.velocity; - self.velocity = '0 0 0'; - if (!self.dest) - self.dest = '0 0 -300'; - self.angles = '0 0 0'; - self.movetype = MOVETYPE_NONE; - self.solid = SOLID_NOT; - SetBrushEntityModel(); - if (!self.cnt) - self.cnt = 12; - if (!self.count) - self.count = 2000; - self.count = 0.01 * self.count * (self.size_x / 1024) * (self.size_y / 1024); - if (self.count < 1) - self.count = 1; - if(self.count > 65535) - self.count = 65535; - - self.state = 0; // 1 is rain, 0 is snow - self.Version = 1; - - Net_LinkEntity(self, FALSE, 0, rainsnow_SendEntity); -} - -.float modelscale; -void misc_laser_aim() -{ - vector a; - if(self.enemy) - { - if(self.spawnflags & 2) - { - if(self.enemy.origin != self.mangle) - { - self.mangle = self.enemy.origin; - self.SendFlags |= 2; - } - } - else - { - a = vectoangles(self.enemy.origin - self.origin); - a_x = -a_x; - if(a != self.mangle) - { - self.mangle = a; - self.SendFlags |= 2; - } - } - } - else - { - if(self.angles != self.mangle) - { - self.mangle = self.angles; - self.SendFlags |= 2; - } - } - if(self.origin != self.oldorigin) - { - self.SendFlags |= 1; - self.oldorigin = self.origin; - } -} - -void misc_laser_init() -{ - if(self.target != "") - self.enemy = find(world, targetname, self.target); -} - -.entity pusher; -void misc_laser_think() -{ - vector o; - entity oldself; - entity hitent; - vector hitloc; - - self.nextthink = time; - - if(!self.state) - return; - - misc_laser_aim(); - - if(self.enemy) - { - o = self.enemy.origin; - if (!(self.spawnflags & 2)) - o = self.origin + normalize(o - self.origin) * 32768; - } - else - { - makevectors(self.mangle); - o = self.origin + v_forward * 32768; - } - - if(self.dmg || self.enemy.target != "") - { - traceline(self.origin, o, MOVE_NORMAL, self); - } - hitent = trace_ent; - hitloc = trace_endpos; - - if(self.enemy.target != "") // DETECTOR laser - { - if(trace_ent.iscreature) - { - self.pusher = hitent; - if(!self.count) - { - self.count = 1; - - oldself = self; - self = self.enemy; - activator = self.pusher; - SUB_UseTargets(); - self = oldself; - } - } - else - { - if(self.count) - { - self.count = 0; - - oldself = self; - self = self.enemy; - activator = self.pusher; - SUB_UseTargets(); - self = oldself; - } - } - } - - if(self.dmg) - { - if(self.team) - if(((self.spawnflags & 8) == 0) == (self.team != hitent.team)) - return; - if(hitent.takedamage) - Damage(hitent, self, self, ((self.dmg < 0) ? 100000 : (self.dmg * frametime)), DEATH_HURTTRIGGER, hitloc, '0 0 0'); - } -} - -float laser_SendEntity(entity to, float fl) -{ - WriteByte(MSG_ENTITY, ENT_CLIENT_LASER); - fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser - if(self.spawnflags & 2) - fl |= 0x80; - if(self.alpha) - fl |= 0x40; - if(self.scale != 1 || self.modelscale != 1) - fl |= 0x20; - if(self.spawnflags & 4) - fl |= 0x10; - WriteByte(MSG_ENTITY, fl); - if(fl & 1) - { - WriteCoord(MSG_ENTITY, self.origin_x); - WriteCoord(MSG_ENTITY, self.origin_y); - WriteCoord(MSG_ENTITY, self.origin_z); - } - if(fl & 8) - { - WriteByte(MSG_ENTITY, self.colormod_x * 255.0); - WriteByte(MSG_ENTITY, self.colormod_y * 255.0); - WriteByte(MSG_ENTITY, self.colormod_z * 255.0); - if(fl & 0x40) - WriteByte(MSG_ENTITY, self.alpha * 255.0); - if(fl & 0x20) - { - WriteByte(MSG_ENTITY, bound(0, self.scale * 16.0, 255)); - WriteByte(MSG_ENTITY, bound(0, self.modelscale * 16.0, 255)); - } - if((fl & 0x80) || !(fl & 0x10)) // effect doesn't need sending if the laser is infinite and has collision testing turned off - WriteShort(MSG_ENTITY, self.cnt + 1); - } - if(fl & 2) - { - if(fl & 0x80) - { - WriteCoord(MSG_ENTITY, self.enemy.origin_x); - WriteCoord(MSG_ENTITY, self.enemy.origin_y); - WriteCoord(MSG_ENTITY, self.enemy.origin_z); - } - else - { - WriteAngle(MSG_ENTITY, self.mangle_x); - WriteAngle(MSG_ENTITY, self.mangle_y); - } - } - if(fl & 4) - WriteByte(MSG_ENTITY, self.state); - return 1; -} - -/*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED -Any object touching the beam will be hurt -Keys: -"target" - spawnfunc_target_position where the laser ends -"mdl" - name of beam end effect to use -"colormod" - color of the beam (default: red) -"dmg" - damage per second (-1 for a laser that kills immediately) -*/ -void laser_use() -{ - self.state = !self.state; - self.SendFlags |= 4; - misc_laser_aim(); -} - -void laser_reset() -{ - if(self.spawnflags & 1) - self.state = 1; - else - self.state = 0; -} - -void spawnfunc_misc_laser() -{ - if(self.mdl) - { - if(self.mdl == "none") - self.cnt = -1; - else - { - self.cnt = particleeffectnum(self.mdl); - if(self.cnt < 0) - if(self.dmg) - self.cnt = particleeffectnum("laser_deadly"); - } - } - else if(!self.cnt) - { - if(self.dmg) - self.cnt = particleeffectnum("laser_deadly"); - else - self.cnt = -1; - } - if(self.cnt < 0) - self.cnt = -1; - - if(self.colormod == '0 0 0') - if(!self.alpha) - self.colormod = '1 0 0'; - if(self.message == "") - self.message = "saw the light"; - if (self.message2 == "") - self.message2 = "was pushed into a laser by"; - if(!self.scale) - self.scale = 1; - if(!self.modelscale) - self.modelscale = 1; - else if(self.modelscale < 0) - self.modelscale = 0; - self.think = misc_laser_think; - self.nextthink = time; - InitializeEntity(self, misc_laser_init, INITPRIO_FINDTARGET); - - self.mangle = self.angles; - - Net_LinkEntity(self, FALSE, 0, laser_SendEntity); - - IFTARGETED - { - self.reset = laser_reset; - laser_reset(); - self.use = laser_use; - } - else - self.state = 1; -} - -// tZorks trigger impulse / gravity -.float radius; -.float falloff; -.float strength; -.float lastpushtime; - -// targeted (directional) mode -void trigger_impulse_touch1() -{ - entity targ; - float pushdeltatime; - float str; - - if (self.active != ACTIVE_ACTIVE) - return; - - if (!isPushable(other)) - return; - - EXACTTRIGGER_TOUCH; - - targ = find(world, targetname, self.target); - if(!targ) - { - objerror("trigger_force without a (valid) .target!\n"); - remove(self); - return; - } - - str = min(self.radius, vlen(self.origin - other.origin)); - - if(self.falloff == 1) - str = (str / self.radius) * self.strength; - else if(self.falloff == 2) - str = (1 - (str / self.radius)) * self.strength; - else - str = self.strength; - - pushdeltatime = time - other.lastpushtime; - if (pushdeltatime > 0.15) pushdeltatime = 0; - other.lastpushtime = time; - if(!pushdeltatime) return; - - other.velocity = other.velocity + normalize(targ.origin - self.origin) * str * pushdeltatime; - other.flags &= ~FL_ONGROUND; - UpdateCSQCProjectile(other); -} - -// Directionless (accelerator/decelerator) mode -void trigger_impulse_touch2() -{ - float pushdeltatime; - - if (self.active != ACTIVE_ACTIVE) - return; - - if (!isPushable(other)) - return; - - EXACTTRIGGER_TOUCH; - - pushdeltatime = time - other.lastpushtime; - if (pushdeltatime > 0.15) pushdeltatime = 0; - other.lastpushtime = time; - if(!pushdeltatime) return; - - // div0: ticrate independent, 1 = identity (not 20) - other.velocity = other.velocity * pow(self.strength, pushdeltatime); - UpdateCSQCProjectile(other); -} - -// Spherical (gravity/repulsor) mode -void trigger_impulse_touch3() -{ - float pushdeltatime; - float str; - - if (self.active != ACTIVE_ACTIVE) - return; - - if (!isPushable(other)) - return; - - EXACTTRIGGER_TOUCH; - - pushdeltatime = time - other.lastpushtime; - if (pushdeltatime > 0.15) pushdeltatime = 0; - other.lastpushtime = time; - if(!pushdeltatime) return; - - setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius); - - str = min(self.radius, vlen(self.origin - other.origin)); - - if(self.falloff == 1) - str = (1 - str / self.radius) * self.strength; // 1 in the inside - else if(self.falloff == 2) - str = (str / self.radius) * self.strength; // 0 in the inside - else - str = self.strength; - - other.velocity = other.velocity + normalize(other.origin - self.origin) * str * pushdeltatime; - UpdateCSQCProjectile(other); -} - -/*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ? --------- KEYS -------- -target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed. - If not, this trigger acts like a damper/accelerator field. - -strength : This is how mutch force to add in the direction of .target each second - when .target is set. If not, this is hoe mutch to slow down/accelerate - someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble) - -radius : If set, act as a spherical device rather then a liniar one. - -falloff : 0 = none, 1 = liniar, 2 = inverted liniar - --------- NOTES -------- -Use a brush textured with common/origin in the trigger entity to determine the origin of the force -in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect). -*/ - -void spawnfunc_trigger_impulse() -{ - self.active = ACTIVE_ACTIVE; - - EXACTTRIGGER_INIT; - if(self.radius) - { - if(!self.strength) self.strength = 2000 * autocvar_g_triggerimpulse_radial_multiplier; - setorigin(self, self.origin); - setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius); - self.touch = trigger_impulse_touch3; - } - else - { - if(self.target) - { - if(!self.strength) self.strength = 950 * autocvar_g_triggerimpulse_directional_multiplier; - self.touch = trigger_impulse_touch1; - } - else - { - if(!self.strength) self.strength = 0.9; - self.strength = pow(self.strength, autocvar_g_triggerimpulse_accel_power) * autocvar_g_triggerimpulse_accel_multiplier; - self.touch = trigger_impulse_touch2; - } - } -} - -/*QUAKED spawnfunc_trigger_flipflop (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ENABLED -"Flip-flop" trigger gate... lets only every second trigger event through -*/ -void flipflop_use() -{ - self.state = !self.state; - if(self.state) - SUB_UseTargets(); -} - -void spawnfunc_trigger_flipflop() -{ - if(self.spawnflags & 1) - self.state = 1; - self.use = flipflop_use; - self.reset = spawnfunc_trigger_flipflop; // perfect resetter -} - -/*QUAKED spawnfunc_trigger_monoflop (.5 .5 .5) (-8 -8 -8) (8 8 8) -"Mono-flop" trigger gate... turns one trigger event into one "on" and one "off" event, separated by a delay of "wait" -*/ -void monoflop_use() -{ - self.nextthink = time + self.wait; - self.enemy = activator; - if(self.state) - return; - self.state = 1; - SUB_UseTargets(); -} -void monoflop_fixed_use() -{ - if(self.state) - return; - self.nextthink = time + self.wait; - self.state = 1; - self.enemy = activator; - SUB_UseTargets(); -} - -void monoflop_think() -{ - self.state = 0; - activator = self.enemy; - SUB_UseTargets(); -} - -void monoflop_reset() -{ - self.state = 0; - self.nextthink = 0; -} - -void spawnfunc_trigger_monoflop() -{ - if(!self.wait) - self.wait = 1; - if(self.spawnflags & 1) - self.use = monoflop_fixed_use; - else - self.use = monoflop_use; - self.think = monoflop_think; - self.state = 0; - self.reset = monoflop_reset; -} - -void multivibrator_send() -{ - float newstate; - float cyclestart; - - cyclestart = floor((time + self.phase) / (self.wait + self.respawntime)) * (self.wait + self.respawntime) - self.phase; - - newstate = (time < cyclestart + self.wait); - - activator = self; - if(self.state != newstate) - SUB_UseTargets(); - self.state = newstate; - - if(self.state) - self.nextthink = cyclestart + self.wait + 0.01; - else - self.nextthink = cyclestart + self.wait + self.respawntime + 0.01; -} - -void multivibrator_toggle() -{ - if(self.nextthink == 0) - { - multivibrator_send(); - } - else - { - if(self.state) - { - SUB_UseTargets(); - self.state = 0; - } - self.nextthink = 0; - } -} - -void multivibrator_reset() -{ - if(!(self.spawnflags & 1)) - self.nextthink = 0; // wait for a trigger event - else - self.nextthink = max(1, time); -} - -/*QUAKED trigger_multivibrator (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ON -"Multivibrator" trigger gate... repeatedly sends trigger events. When triggered, turns on or off. --------- KEYS -------- -target: trigger all entities with this targetname when it goes off -targetname: name that identifies this entity so it can be triggered; when off, it always uses the OFF state -phase: offset of the timing -wait: "on" cycle time (default: 1) -respawntime: "off" cycle time (default: same as wait) --------- SPAWNFLAGS -------- -START_ON: assume it is already turned on (when targeted) -*/ -void spawnfunc_trigger_multivibrator() -{ - if(!self.wait) - self.wait = 1; - if(!self.respawntime) - self.respawntime = self.wait; - - self.state = 0; - self.use = multivibrator_toggle; - self.think = multivibrator_send; - self.nextthink = max(1, time); - - IFTARGETED - multivibrator_reset(); -} - - -void follow_init() -{ - entity src, dst; - src = world; - dst = world; - if(self.killtarget != "") - src = find(world, targetname, self.killtarget); - if(self.target != "") - dst = find(world, targetname, self.target); - - if(!src && !dst) - { - objerror("follow: could not find target/killtarget"); - return; - } - - if(self.jointtype) - { - // already done :P entity must stay - self.aiment = src; - self.enemy = dst; - } - else if(!src || !dst) - { - objerror("follow: could not find target/killtarget"); - return; - } - else if(self.spawnflags & 1) - { - // attach - if(self.spawnflags & 2) - { - setattachment(dst, src, self.message); - } - else - { - attach_sameorigin(dst, src, self.message); - } - - dst.solid = SOLID_NOT; // solid doesn't work with attachment - remove(self); - } - else - { - if(self.spawnflags & 2) - { - dst.movetype = MOVETYPE_FOLLOW; - dst.aiment = src; - // dst.punchangle = '0 0 0'; // keep unchanged - dst.view_ofs = dst.origin; - dst.v_angle = dst.angles; - } - else - { - follow_sameorigin(dst, src); - } - - remove(self); - } -} - -void spawnfunc_misc_follow() -{ - InitializeEntity(self, follow_init, INITPRIO_FINDTARGET); -} - - - -void gamestart_use() { - activator = self; - SUB_UseTargets(); - remove(self); -} - -void spawnfunc_trigger_gamestart() { - self.use = gamestart_use; - self.reset2 = spawnfunc_trigger_gamestart; - - if(self.wait) - { - self.think = self.use; - self.nextthink = game_starttime + self.wait; - } - else - InitializeEntity(self, gamestart_use, INITPRIO_FINDTARGET); -} - - - - -.entity voicescript; // attached voice script -.float voicescript_index; // index of next voice, or -1 to use the randomized ones -.float voicescript_nextthink; // time to play next voice -.float voicescript_voiceend; // time when this voice ends - -void target_voicescript_clear(entity pl) -{ - pl.voicescript = world; -} - -void target_voicescript_use() -{ - if(activator.voicescript != self) - { - activator.voicescript = self; - activator.voicescript_index = 0; - activator.voicescript_nextthink = time + self.delay; - } -} - -void target_voicescript_next(entity pl) -{ - entity vs; - float i, n, dt; - - vs = pl.voicescript; - if(!vs) - return; - if(vs.message == "") - return; - if (!IS_PLAYER(pl)) - return; - if(gameover) - return; - - if(time >= pl.voicescript_voiceend) - { - if(time >= pl.voicescript_nextthink) - { - // get the next voice... - n = tokenize_console(vs.message); - - if(pl.voicescript_index < vs.cnt) - i = pl.voicescript_index * 2; - else if(n > vs.cnt * 2) - i = ((pl.voicescript_index - vs.cnt) % ((n - vs.cnt * 2 - 1) / 2)) * 2 + vs.cnt * 2 + 1; - else - i = -1; - - if(i >= 0) - { - play2(pl, strcat(vs.netname, "/", argv(i), ".wav")); - dt = stof(argv(i + 1)); - if(dt >= 0) - { - pl.voicescript_voiceend = time + dt; - pl.voicescript_nextthink = pl.voicescript_voiceend + vs.wait * (0.5 + random()); - } - else - { - pl.voicescript_voiceend = time - dt; - pl.voicescript_nextthink = pl.voicescript_voiceend; - } - - pl.voicescript_index += 1; - } - else - { - pl.voicescript = world; // stop trying then - } - } - } -} - -void spawnfunc_target_voicescript() -{ - // netname: directory of the sound files - // message: list of "sound file" duration "sound file" duration, a *, and again a list - // foo1 4.1 foo2 4.0 foo3 -3.1 * fool1 1.1 fool2 7.1 fool3 9.1 fool4 3.7 - // Here, a - in front of the duration means that no delay is to be - // added after this message - // wait: average time between messages - // delay: initial delay before the first message - - float i, n; - self.use = target_voicescript_use; - - n = tokenize_console(self.message); - self.cnt = n / 2; - for(i = 0; i+1 < n; i += 2) - { - if(argv(i) == "*") - { - self.cnt = i / 2; - ++i; - } - precache_sound(strcat(self.netname, "/", argv(i), ".wav")); - } -} - - - -void trigger_relay_teamcheck_use() -{ - if(activator.team) - { - if(self.spawnflags & 2) - { - if(activator.team != self.team) - SUB_UseTargets(); - } - else - { - if(activator.team == self.team) - SUB_UseTargets(); - } - } - else - { - if(self.spawnflags & 1) - SUB_UseTargets(); - } -} - -void trigger_relay_teamcheck_reset() -{ - self.team = self.team_saved; -} - -void spawnfunc_trigger_relay_teamcheck() -{ - self.team_saved = self.team; - self.use = trigger_relay_teamcheck_use; - self.reset = trigger_relay_teamcheck_reset; -} - - - -void trigger_disablerelay_use() -{ - entity e; - - float a, b; - a = b = 0; - - for(e = world; (e = find(e, targetname, self.target)); ) - { - if(e.use == SUB_UseTargets) - { - e.use = SUB_DontUseTargets; - ++a; - } - else if(e.use == SUB_DontUseTargets) - { - e.use = SUB_UseTargets; - ++b; - } - } - - if((!a) == (!b)) - print("Invalid use of trigger_disablerelay: ", ftos(a), " relays were on, ", ftos(b), " relays were off!\n"); -} - -void spawnfunc_trigger_disablerelay() -{ - self.use = trigger_disablerelay_use; -} - -float magicear_matched; -float W_Tuba_HasPlayed(entity pl, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo); -string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin) -{ - float domatch, dotrigger, matchstart, l; - string s, msg; - entity oldself; - string savemessage; - - magicear_matched = FALSE; - - dotrigger = ((IS_PLAYER(source)) && (source.deadflag == DEAD_NO) && ((ear.radius == 0) || (vlen(source.origin - ear.origin) <= ear.radius))); - domatch = ((ear.spawnflags & 32) || dotrigger); - - if (!domatch) - return msgin; - - if (!msgin) - { - // we are in TUBA mode! - if (!(ear.spawnflags & 256)) - return msgin; - - if(!W_Tuba_HasPlayed(source, ear.message, ear.movedir_x, !(ear.spawnflags & 512), ear.movedir_y, ear.movedir_z)) - return msgin; - - magicear_matched = TRUE; - - if(dotrigger) - { - oldself = self; - activator = source; - self = ear; - savemessage = self.message; - self.message = string_null; - SUB_UseTargets(); - self.message = savemessage; - self = oldself; - } - - if(ear.netname != "") - return ear.netname; - - return msgin; - } - - if(ear.spawnflags & 256) // ENOTUBA - return msgin; - - if(privatesay) - { - if(ear.spawnflags & 4) - return msgin; - } - else - { - if(!teamsay) - if(ear.spawnflags & 1) - return msgin; - if(teamsay > 0) - if(ear.spawnflags & 2) - return msgin; - if(teamsay < 0) - if(ear.spawnflags & 8) - return msgin; - } - - matchstart = -1; - l = strlen(ear.message); - - if(ear.spawnflags & 128) - msg = msgin; - else - msg = strdecolorize(msgin); - - if(substring(ear.message, 0, 1) == "*") - { - if(substring(ear.message, -1, 1) == "*") - { - // two wildcards - // as we need multi-replacement here... - s = substring(ear.message, 1, -2); - l -= 2; - if(strstrofs(msg, s, 0) >= 0) - matchstart = -2; // we use strreplace on s - } - else - { - // match at start - s = substring(ear.message, 1, -1); - l -= 1; - if(substring(msg, -l, l) == s) - matchstart = strlen(msg) - l; - } - } - else - { - if(substring(ear.message, -1, 1) == "*") - { - // match at end - s = substring(ear.message, 0, -2); - l -= 1; - if(substring(msg, 0, l) == s) - matchstart = 0; - } - else - { - // full match - s = ear.message; - if(msg == ear.message) - matchstart = 0; - } - } - - if(matchstart == -1) // no match - return msgin; - - magicear_matched = TRUE; - - if(dotrigger) - { - oldself = self; - activator = source; - self = ear; - savemessage = self.message; - self.message = string_null; - SUB_UseTargets(); - self.message = savemessage; - self = oldself; - } - - if(ear.spawnflags & 16) - { - return ear.netname; - } - else if(ear.netname != "") - { - if(matchstart < 0) - return strreplace(s, ear.netname, msg); - else - return strcat( - substring(msg, 0, matchstart), - ear.netname, - substring(msg, matchstart + l, -1) - ); - } - else - return msgin; -} - -entity magicears; -string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin) -{ - entity ear; - string msgout; - for(ear = magicears; ear; ear = ear.enemy) - { - msgout = trigger_magicear_processmessage(ear, source, teamsay, privatesay, msgin); - if(!(ear.spawnflags & 64)) - if(magicear_matched) - return msgout; - msgin = msgout; - } - return msgin; -} - -void spawnfunc_trigger_magicear() -{ - self.enemy = magicears; - magicears = self; - - // actually handled in "say" processing - // spawnflags: - // 1 = ignore say - // 2 = ignore teamsay - // 4 = ignore tell - // 8 = ignore tell to unknown player - // 16 = let netname replace the whole message (otherwise, netname is a word replacement if set) - // 32 = perform the replacement even if outside the radius or dead - // 64 = continue replacing/triggering even if this one matched - // 128 = don't decolorize message before matching - // 256 = message is a tuba note sequence (pitch.duration pitch.duration ...) - // 512 = tuba notes must be exact right pitch, no transposing - // message: either - // *pattern* - // or - // *pattern - // or - // pattern* - // or - // pattern - // netname: - // if set, replacement for the matched text - // radius: - // "hearing distance" - // target: - // what to trigger - // movedir: - // for spawnflags 256, defines 'instrument+1 mintempo maxtempo' (zero component doesn't matter) - - self.movedir_x -= 1; // map to tuba instrument numbers -} - -void relay_activators_use() -{ - entity trg, os; - - os = self; - - for(trg = world; (trg = find(trg, targetname, os.target)); ) - { - self = trg; - if (trg.setactive) - trg.setactive(os.cnt); - else - { - //bprint("Not using setactive\n"); - if(os.cnt == ACTIVE_TOGGLE) - if(trg.active == ACTIVE_ACTIVE) - trg.active = ACTIVE_NOT; - else - trg.active = ACTIVE_ACTIVE; - else - trg.active = os.cnt; - } - } - self = os; -} - -void spawnfunc_relay_activate() -{ - self.cnt = ACTIVE_ACTIVE; - self.use = relay_activators_use; -} - -void spawnfunc_relay_deactivate() -{ - self.cnt = ACTIVE_NOT; - self.use = relay_activators_use; -} - -void spawnfunc_relay_activatetoggle() -{ - self.cnt = ACTIVE_TOGGLE; - self.use = relay_activators_use; -} - -.string chmap, gametype; -void spawnfunc_target_changelevel_use() -{ - if(self.gametype != "") - MapInfo_SwitchGameType(MapInfo_Type_FromString(self.gametype)); - - if (self.chmap == "") - localcmd("endmatch\n"); - else - localcmd(strcat("changelevel ", self.chmap, "\n")); -} - -void spawnfunc_target_changelevel() -{ - self.use = spawnfunc_target_changelevel_use; -} diff --git a/qcsrc/server/item_key.qh b/qcsrc/server/item_key.qh index 24ef1e935..f0569291d 100644 --- a/qcsrc/server/item_key.qh +++ b/qcsrc/server/item_key.qh @@ -8,7 +8,9 @@ /** * list of key names. */ +#ifdef SVQC string item_keys_names[ITEM_KEY_MAX]; +#endif /** * Use keys from p on l. diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index eacebb5ec..fe21d088c 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -1562,7 +1562,6 @@ void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer) .float nottargeted; #define IFTARGETED if(!self.nottargeted && self.targetname != "") -void() SUB_Remove; void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc) { vector mi, ma; diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index f61d2609d..073982116 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -80,6 +80,8 @@ anticheat.qh cheats.qh ../common/playerstats.qh +../common/triggers/include.qh + portals.qh g_hook.qh // TODO @@ -143,7 +145,6 @@ t_teleporters.qc sv_main.qc -g_triggers.qc g_models.qc // singleplayer stuff @@ -163,8 +164,6 @@ weapons/weaponsystem.qc ../common/weapons/config.qc ../common/weapons/weapons.qc // TODO -../common/triggers/include.qh - t_items.qc cl_impulse.qc diff --git a/qcsrc/server/tturrets/system/system_misc.qc b/qcsrc/server/tturrets/system/system_misc.qc index 3fdd5eb1e..bb4b65a2c 100644 --- a/qcsrc/server/tturrets/system/system_misc.qc +++ b/qcsrc/server/tturrets/system/system_misc.qc @@ -229,7 +229,6 @@ void turrets_precash() #ifdef TURRET_DEBUG -void SUB_Remove(); void marker_think() { if(self.cnt)