Merge branch 'TimePath/experiments/csqc_prediction' into Mario/qc_physics
authorMario <zacjardine@y7mail.com>
Tue, 17 Feb 2015 19:45:21 +0000 (06:45 +1100)
committerMario <zacjardine@y7mail.com>
Tue, 17 Feb 2015 19:45:21 +0000 (06:45 +1100)
Conflicts:
qcsrc/client/bgmscript.qh
qcsrc/client/command/cl_cmd.qc
qcsrc/client/damage.qc
qcsrc/client/main.qc
qcsrc/client/progs.src
qcsrc/client/waypointsprites.qc
qcsrc/common/constants.qh
qcsrc/common/physics.qh
qcsrc/common/triggers/func/breakable.qc
qcsrc/common/triggers/target/music.qc
qcsrc/common/triggers/target/spawn.qc
qcsrc/common/triggers/trigger/jumppads.qc
qcsrc/common/triggers/trigger/secret.qc
qcsrc/common/triggers/trigger/secret.qh
qcsrc/common/triggers/trigger/swamp.qc
qcsrc/server/constants.qh
qcsrc/server/g_subs.qc
qcsrc/server/g_triggers.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/progs.src
qcsrc/server/t_halflife.qc
qcsrc/server/t_plats.qc

84 files changed:
1  2 
qcsrc/client/bgmscript.qc
qcsrc/client/bgmscript.qh
qcsrc/client/command/cl_cmd.qc
qcsrc/client/damage.qc
qcsrc/client/effects.qc
qcsrc/client/main.qc
qcsrc/client/progs.src
qcsrc/client/waypointsprites.qc
qcsrc/common/constants.qh
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/net_notice.qc
qcsrc/common/physics.qc
qcsrc/common/physics.qh
qcsrc/common/triggers/func/breakable.qc
qcsrc/common/triggers/func/conveyor.qc
qcsrc/common/triggers/func/door.qc
qcsrc/common/triggers/func/door_secret.qc
qcsrc/common/triggers/func/include.qc
qcsrc/common/triggers/func/include.qh
qcsrc/common/triggers/func/ladder.qc
qcsrc/common/triggers/func/plat.qc
qcsrc/common/triggers/func/rainsnow.qc
qcsrc/common/triggers/func/train.qc
qcsrc/common/triggers/include.qc
qcsrc/common/triggers/include.qh
qcsrc/common/triggers/misc/include.qc
qcsrc/common/triggers/misc/include.qh
qcsrc/common/triggers/misc/laser.qc
qcsrc/common/triggers/platforms.qc
qcsrc/common/triggers/platforms.qh
qcsrc/common/triggers/subs.qh
qcsrc/common/triggers/target/include.qc
qcsrc/common/triggers/target/include.qh
qcsrc/common/triggers/target/music.qc
qcsrc/common/triggers/target/music.qh
qcsrc/common/triggers/target/spawn.qc
qcsrc/common/triggers/trigger/gravity.qc
qcsrc/common/triggers/trigger/hurt.qc
qcsrc/common/triggers/trigger/impulse.qc
qcsrc/common/triggers/trigger/impulse.qh
qcsrc/common/triggers/trigger/include.qc
qcsrc/common/triggers/trigger/include.qh
qcsrc/common/triggers/trigger/jumppads.qc
qcsrc/common/triggers/trigger/jumppads.qh
qcsrc/common/triggers/trigger/magicear.qc
qcsrc/common/triggers/trigger/secret.qc
qcsrc/common/triggers/trigger/secret.qh
qcsrc/common/triggers/trigger/swamp.qc
qcsrc/common/triggers/trigger/swamp.qh
qcsrc/common/triggers/triggers.qh
qcsrc/common/weapons/w_porto.qc
qcsrc/server/bot/havocbot/havocbot.qc
qcsrc/server/cheats.qc
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/constants.qh
qcsrc/server/defs.qh
qcsrc/server/g_hook.qc
qcsrc/server/g_models.qc
qcsrc/server/g_subs.qc
qcsrc/server/g_subs.qh
qcsrc/server/g_world.qc
qcsrc/server/item_key.qc
qcsrc/server/item_key.qh
qcsrc/server/miscfunctions.qc
qcsrc/server/miscfunctions.qh
qcsrc/server/mutators/gamemode_assault.qc
qcsrc/server/mutators/gamemode_domination.qc
qcsrc/server/mutators/gamemode_onslaught.qc
qcsrc/server/mutators/mutator_buffs.qc
qcsrc/server/mutators/mutator_nades.qc
qcsrc/server/mutators/mutators_include.qc
qcsrc/server/progs.src
qcsrc/server/race.qc
qcsrc/server/spawnpoints.qc
qcsrc/server/t_items.qc
qcsrc/server/t_jumppads.qh
qcsrc/server/t_teleporters.qc
qcsrc/server/tturrets/system/system_main.qc
qcsrc/server/tturrets/system/system_misc.qc
qcsrc/server/vehicles/racer.qc
qcsrc/server/vehicles/vehicles.qc
qcsrc/warpzonelib/common.qc
qcsrc/warpzonelib/server.qc

@@@ -1,3 -1,14 +1,15 @@@
+ #if defined(CSQC)
+       #include "../dpdefs/csprogsdefs.qh"
+       #include "defs.qh"
++      #include "../common/triggers/triggers.qh"
+       #include "../common/util.qh"
+       #include "autocvars.qh"
+       #include "bgmscript.qh"
+       #include "main.qh"
+ #elif defined(MENUQC)
+ #elif defined(SVQC)
+ #endif
  #define CONSTANT_SPEED_DECAY
  
  float bgmscriptbuf;
@@@ -1,3 -1,12 +1,6 @@@
 -.string bgmscript;
 -.float bgmscriptattack;
 -.float bgmscriptdecay;
 -.float bgmscriptsustain;
 -.float bgmscriptrelease;
 -
+ #ifndef BGMSCRIPT_H
+ #define BGMSCRIPT_H
  .float just_toggled;
  
  void BGMScript_InitEntity(entity e);
@@@ -337,32 -339,7 +339,32 @@@ void LocalCommand_mv_download(int reque
        }
  }
  
- void LocalCommand_find(float request, float argc)
++void LocalCommand_find(int request, int argc)
 +{
 +      switch(request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      entity client;
 +
 +                      for(client = world; (client = find(client, classname, argv(1))); )
 +                              print(etos(client), "\n");
 +
 +                      return;
 +              }
 +
 +              default:
 +                      print("Incorrect parameters for ^2find^7\n");
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      print("\nUsage:^3 cl_cmd find classname\n");
 +                      print("  Where 'classname' is the classname to search for.\n");
 +                      return;
 +              }
 +      }
 +}
 +
- void LocalCommand_sendcvar(float request, float argc)
+ void LocalCommand_sendcvar(int request, int argc)
  {
        switch(request)
        {
@@@ -31,7 -47,7 +47,7 @@@ void DamageEffect_Think(
        pointparticles(self.team, org, '0 0 0', 1);
  }
  
- void DamageEffect(vector hitorg, float thedamage, float type, float specnum)
 -void DamageEffect(vector hitorg, float dmg, int type, int specnum)
++void DamageEffect(vector hitorg, float thedamage, int type, int specnum)
  {
        // particle effects for players and objects damaged by weapons (eg: flames coming out of victims shot with rockets)
  
  
  void Ent_DamageInfo(float isNew)
  {
-       float thedamage, rad, edge, thisdmg, forcemul, species, hitplayer = FALSE;
 -      float dmg, rad, edge, thisdmg;
++      float thedamage, rad, edge, thisdmg;
+       bool hitplayer = false;
+       int species, forcemul;
        vector force, thisforce;
        entity oldself;
  
        w_issilent = (w_deathtype & 0x8000);
        w_deathtype = (w_deathtype & 0x7FFF);
  
-       w_org_x = ReadCoord();
-       w_org_y = ReadCoord();
-       w_org_z = ReadCoord();
+       w_org.x = ReadCoord();
+       w_org.y = ReadCoord();
+       w_org.z = ReadCoord();
  
 -      dmg = ReadByte();
 +      thedamage = ReadByte();
        rad = ReadByte();
        edge = ReadByte();
        force = decompressShortVector(ReadShort());
Simple merge
index 0000000,e5c875b..3903cb4
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1350 +1,1331 @@@
 -void trigger_touch_generic(void() touchfunc)
 -{
 -      entity e;
 -      for(e = findradius((self.absmin + self.absmax) * 0.5, vlen(self.absmax - self.absmin) * 0.5 + 1); e; e = e.chain)
 -      if(e.isplayermodel)
 -      {
 -              vector emin = e.absmin, emax = e.absmax;
 -              if(self.solid == SOLID_BSP)
 -              {
 -                      emin -= '1 1 1';
 -                      emax += '1 1 1';
 -              }
 -              if(boxesoverlap(emin, emax, self.absmin, self.absmax)) // quick
 -              if(WarpZoneLib_BoxTouchesBrush(emin, emax, self, e)) // accurate
 -              {
 -                      other = e;
 -                      touchfunc();
 -              }
 -      }
 -}
+ #include "mapvoting.qh"
+ #include "modeleffects.qh"
+ #include "particles.qh"
+ #include "scoreboard.qh"
+ #include "shownames.qh"
+ #include "target_music.qh"
+ #include "tturrets.qh"
+ #include "tuba.qh"
+ #include "wall.qh"
+ #include "waypointsprites.qh"
+ #include "vehicles/vehicles.qh"
+ #include "../server/vehicles/bumblebee.qh"
+ #include "../common/net_notice.qh"
+ #include "../common/monsters/monsters.qh"
++#include "../common/triggers/include.qh"
++
+ #include "../warpzonelib/client.qh"
+ // --------------------------------------------------------------------------
+ // BEGIN REQUIRED CSQC FUNCTIONS
+ //include "main.qh"
+ entity clearentity_ent;
+ void clearentity(entity e)
+ {
+       if (!clearentity_ent)
+       {
+               clearentity_ent = spawn();
+               clearentity_ent.classname = "clearentity";
+       }
+       int n = e.entnum;
+       copyentity(clearentity_ent, e);
+       e.entnum = n;
+ }
+ #define DP_CSQC_ENTITY_REMOVE_IS_B0RKED
+ void menu_show_error()
+ {
+       drawstring('0 200 0', _("ERROR - MENU IS VISIBLE BUT NO MENU WAS DEFINED!"), '8 8 0', '1 0 0', 1, 0);
+ }
+ // CSQC_Init : Called every time the CSQC code is initialized (essentially at map load)
+ // Useful for precaching things
+ void menu_sub_null()
+ {
+ }
+ string forcefog;
+ void WaypointSprite_Load();
+ void ConsoleCommand_macro_init();
+ void CSQC_Init(void)
+ {
+       prvm_language = cvar_string("prvm_language");
+ #ifdef WATERMARK
+       dprintf("^4CSQC Build information: ^1%s\n", WATERMARK);
+ #endif
+       int i;
+       binddb = db_create();
+       tempdb = db_create();
+       ClientProgsDB = db_load("client.db");
+       compressShortVector_init();
+       draw_endBoldFont();
+       menu_visible = false;
+       menu_show = menu_show_error;
+       menu_action = func_null;
+       for(i = 0; i < 255; ++i)
+               if(getplayerkeyvalue(i, "viewentity") == "")
+                       break;
+       maxclients = i;
+       //registercommand("hud_configure");
+       //registercommand("hud_save");
+       //registercommand("menu_action");
+       ConsoleCommand_macro_init();
+       registercvar("hud_usecsqc", "1");
+       registercvar("scoreboard_columns", "default");
+       registercvar("cl_nade_type", "3");
+       registercvar("cl_pokenade_type", "zombie");
+       gametype = 0;
+       // hud_fields uses strunzone on the titles!
+       for(i = 0; i < MAX_HUD_FIELDS; ++i)
+               hud_title[i] = strzone("(null)");
+       Cmd_HUD_SetFields(0);
+       postinit = false;
+       calledhooks = 0;
+       teams = Sort_Spawn();
+       players = Sort_Spawn();
+       GetTeam(NUM_SPECTATOR, true); // add specs first
+       // needs to be done so early because of the constants they create
+       CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
+       CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
+       CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
+       CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
+       CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
+       CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels);
+       CALL_ACCUMULATED_FUNCTION(RegisterBuffs);
+       WaypointSprite_Load();
+       // precaches
+       precache_model("null");
+       precache_sound("misc/hit.wav");
+       precache_sound("misc/typehit.wav");
+       Projectile_Precache();
+       Hook_Precache();
+       GibSplash_Precache();
+       Casings_Precache();
+       Vehicles_Precache();
+       turrets_precache();
+       Tuba_Precache();
+       CSQCPlayer_Precache();
+       if(autocvar_cl_reticle)
+       {
+               precache_pic("gfx/reticle_normal");
+               // weapon reticles are precached in weapon files
+       }
+       get_mi_min_max_texcoords(1); // try the CLEVER way first
+       minimapname = strcat("gfx/", mi_shortname, "_radar.tga");
+       shortmapname = mi_shortname;
+       if(precache_pic(minimapname) == "")
+       {
+               // but maybe we have a non-clever minimap
+               minimapname = strcat("gfx/", mi_shortname, "_mini.tga");
+               if(precache_pic(minimapname) == "")
+                       minimapname = ""; // FAIL
+               else
+                       get_mi_min_max_texcoords(0); // load new texcoords
+       }
+       mi_center = (mi_min + mi_max) * 0.5;
+       mi_scale = mi_max - mi_min;
+       minimapname = strzone(minimapname);
+       WarpZone_Init();
+       hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
+       hud_configure_prev = -1;
+       draw_currentSkin = strzone(strcat("gfx/menu/", cvar_string("menu_skin")));
+ }
+ // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc)
+ void Shutdown(void)
+ {
+       WarpZone_Shutdown();
+       remove(teams);
+       remove(players);
+       db_close(binddb);
+       db_close(tempdb);
+       if(autocvar_cl_db_saveasdump)
+               db_dump(ClientProgsDB, "client.db");
+       else
+               db_save(ClientProgsDB, "client.db");
+       db_close(ClientProgsDB);
+       if(camera_active)
+               cvar_set("chase_active",ftos(chase_active_backup));
+       // unset the event chasecam's chase_active
+       if(autocvar_chase_active < 0)
+               cvar_set("chase_active", "0");
+       if (!isdemo())
+       {
+               if (!(calledhooks & HOOK_START))
+                       localcmd("\n_cl_hook_gamestart nop\n");
+               if (!(calledhooks & HOOK_END))
+                       localcmd("\ncl_hook_gameend\n");
+       }
+ }
+ .float has_team;
+ float SetTeam(entity o, int Team)
+ {
+       entity tm;
+       if(teamplay)
+       {
+               switch(Team)
+               {
+                       case -1:
+                       case NUM_TEAM_1:
+                       case NUM_TEAM_2:
+                       case NUM_TEAM_3:
+                       case NUM_TEAM_4:
+                               break;
+                       default:
+                               if(GetTeam(Team, false) == world)
+                               {
+                                       dprintf("trying to switch to unsupported team %d\n", Team);
+                                       Team = NUM_SPECTATOR;
+                               }
+                               break;
+               }
+       }
+       else
+       {
+               switch(Team)
+               {
+                       case -1:
+                       case 0:
+                               break;
+                       default:
+                               if(GetTeam(Team, false) == world)
+                               {
+                                       dprintf("trying to switch to unsupported team %d\n", Team);
+                                       Team = NUM_SPECTATOR;
+                               }
+                               break;
+               }
+       }
+       if(Team == -1) // leave
+       {
+               if(o.has_team)
+               {
+                       tm = GetTeam(o.team, false);
+                       tm.team_size -= 1;
+                       o.has_team = 0;
+                       return true;
+               }
+       }
+       else
+       {
+               if (!o.has_team)
+               {
+                       o.team = Team;
+                       tm = GetTeam(Team, true);
+                       tm.team_size += 1;
+                       o.has_team = 1;
+                       return true;
+               }
+               else if(Team != o.team)
+               {
+                       tm = GetTeam(o.team, false);
+                       tm.team_size -= 1;
+                       o.team = Team;
+                       tm = GetTeam(Team, true);
+                       tm.team_size += 1;
+                       return true;
+               }
+       }
+       return false;
+ }
+ void Playerchecker_Think()
+ {
+     int i;
+       entity e;
+       for(i = 0; i < maxclients; ++i)
+       {
+               e = playerslots[i];
+               if(GetPlayerName(i) == "")
+               {
+                       if(e.sort_prev)
+                       {
+                               // player disconnected
+                               SetTeam(e, -1);
+                               RemovePlayer(e);
+                               e.sort_prev = world;
+                               //e.gotscores = 0;
+                       }
+               }
+               else
+               {
+                       if (!e.sort_prev)
+                       {
+                               // player connected
+                               if (!e)
+                                       playerslots[i] = e = spawn();
+                               e.sv_entnum = i;
+                               e.ping = 0;
+                               e.ping_packetloss = 0;
+                               e.ping_movementloss = 0;
+                               //e.gotscores = 0; // we might already have the scores...
+                               SetTeam(e, GetPlayerColor(i)); // will not hurt; later updates come with HUD_UpdatePlayerTeams
+                               RegisterPlayer(e);
+                               HUD_UpdatePlayerPos(e);
+                       }
+               }
+       }
+       self.nextthink = time + 0.2;
+ }
+ void Porto_Init();
+ void TrueAim_Init();
+ void PostInit(void)
+ {
+       entity playerchecker;
+       playerchecker = spawn();
+       playerchecker.think = Playerchecker_Think;
+       playerchecker.nextthink = time + 0.2;
+       Porto_Init();
+       TrueAim_Init();
+       postinit = true;
+ }
+ // CSQC_InputEvent : Used to perform actions based on any key pressed, key released and mouse on the client.
+ // Return value should be 1 if CSQC handled the input, otherwise return 0 to have the input passed to the engine.
+ // All keys are in ascii.
+ // bInputType = 0 is key pressed, 1 is key released, 2 and 3 are mouse input.
+ // In the case of keyboard input, nPrimary is the ascii code, and nSecondary is 0.
+ // In the case of mouse input, nPrimary is xdelta, nSecondary is ydelta.
+ // In the case of mouse input after a setcursormode(1) call, nPrimary is xpos, nSecondary is ypos.
+ float CSQC_InputEvent(float bInputType, float nPrimary, float nSecondary)
+ {
+       float bSkipKey;
+       bSkipKey = false;
+       if (HUD_Panel_InputEvent(bInputType, nPrimary, nSecondary))
+               return true;
+       if (MapVote_InputEvent(bInputType, nPrimary, nSecondary))
+               return true;
+       if(menu_visible && menu_action)
+               if(menu_action(bInputType, nPrimary, nSecondary))
+                       return true;
+       return bSkipKey;
+ }
+ // END REQUIRED CSQC FUNCTIONS
+ // --------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
+ // BEGIN OPTIONAL CSQC FUNCTIONS
 -#ifdef CSQC
 -void ent_func_ladder();
 -void ent_trigger_push();
 -void ent_target_push();
 -void ent_conveyor();
 -#endif
+ void Ent_RemoveEntCS()
+ {
+       entcs_receiver[self.sv_entnum] = world;
+ }
+ void Ent_ReadEntCS()
+ {
+     int sf;
+       InterpolateOrigin_Undo();
+       self.classname = "entcs_receiver";
+       sf = ReadByte();
+       if(sf & 1)
+               self.sv_entnum = ReadByte();
+       if(sf & 2)
+       {
+               self.origin_x = ReadShort();
+               self.origin_y = ReadShort();
+               self.origin_z = ReadShort();
+               setorigin(self, self.origin);
+       }
+       if(sf & 4)
+       {
+               self.angles_y = ReadByte() * 360.0 / 256;
+               self.angles_x = self.angles_z = 0;
+       }
+       if(sf & 8)
+               self.healthvalue = ReadByte() * 10;
+       if(sf & 16)
+               self.armorvalue = ReadByte() * 10;
+       entcs_receiver[self.sv_entnum] = self;
+       self.entremove = Ent_RemoveEntCS;
+       self.iflags |= IFLAG_ORIGIN;
+       InterpolateOrigin_Note();
+ }
+ void Ent_Remove();
+ void Ent_RemovePlayerScore()
+ {
+       if(self.owner) {
+               SetTeam(self.owner, -1);
+               self.owner.gotscores = 0;
+               for(int i = 0; i < MAX_SCORE; ++i) {
+                       self.owner.(scores[i]) = 0; // clear all scores
+               }
+       }
+ }
+ void Ent_ReadPlayerScore()
+ {
+       int i, n;
+       bool isNew;
+       entity o;
+       // damnit -.- don't want to go change every single .sv_entnum in hud.qc AGAIN
+       // (no I've never heard of M-x replace-string, sed, or anything like that)
+       isNew = !self.owner; // workaround for DP bug
+       n = ReadByte()-1;
+ #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED
+       if(!isNew && n != self.sv_entnum)
+       {
+               //print("A CSQC entity changed its owner!\n");
+               printf("A CSQC entity changed its owner! (edict: %d, classname: %s)\n", num_for_edict(self), self.classname);
+               isNew = true;
+               Ent_Remove();
+               self.enttype = ENT_CLIENT_SCORES;
+       }
+ #endif
+       self.sv_entnum = n;
+       if (!(playerslots[self.sv_entnum]))
+               playerslots[self.sv_entnum] = spawn();
+       o = self.owner = playerslots[self.sv_entnum];
+       o.sv_entnum = self.sv_entnum;
+       o.gotscores = 1;
+       //if (!o.sort_prev)
+       //      RegisterPlayer(o);
+       //playerchecker will do this for us later, if it has not already done so
+     int sf, lf;
+ #if MAX_SCORE <= 8
+       sf = ReadByte();
+       lf = ReadByte();
+ #else
+       sf = ReadShort();
+       lf = ReadShort();
+ #endif
+     int p;
+       for(i = 0, p = 1; i < MAX_SCORE; ++i, p *= 2)
+               if(sf & p)
+               {
+                       if(lf & p)
+                               o.(scores[i]) = ReadInt24_t();
+                       else
+                               o.(scores[i]) = ReadChar();
+               }
+       if(o.sort_prev)
+               HUD_UpdatePlayerPos(o); // if not registered, we cannot do this yet!
+       self.entremove = Ent_RemovePlayerScore;
+ }
+ void Ent_ReadTeamScore()
+ {
+       int i;
+       entity o;
+       self.team = ReadByte();
+       o = self.owner = GetTeam(self.team, true); // these team numbers can always be trusted
+     int sf, lf;
+ #if MAX_TEAMSCORE <= 8
+       sf = ReadByte();
+       lf = ReadByte();
+ #else
+       sf = ReadShort();
+       lf = ReadShort();
+ #endif
+       int p;
+       for(i = 0, p = 1; i < MAX_TEAMSCORE; ++i, p *= 2)
+               if(sf & p)
+               {
+                       if(lf & p)
+                               o.(teamscores[i]) = ReadInt24_t();
+                       else
+                               o.(teamscores[i]) = ReadChar();
+               }
+       HUD_UpdateTeamPos(o);
+ }
+ void Ent_ClientData()
+ {
+       float newspectatee_status;
+     int f = ReadByte();
+       scoreboard_showscores_force = (f & 1);
+       if(f & 2)
+       {
+               newspectatee_status = ReadByte();
+               if(newspectatee_status == player_localnum + 1)
+                       newspectatee_status = -1; // observing
+       }
+       else
+               newspectatee_status = 0;
+       spectatorbutton_zoom = (f & 4);
+       if(f & 8)
+       {
+               angles_held_status = 1;
+               angles_held.x = ReadAngle();
+               angles_held.y = ReadAngle();
+               angles_held.z = 0;
+       }
+       else
+               angles_held_status = 0;
+       if(newspectatee_status != spectatee_status)
+       {
+               // clear race stuff
+               race_laptime = 0;
+               race_checkpointtime = 0;
+       }
+       if (autocvar_hud_panel_healtharmor_progressbar_gfx)
+       {
+               if ( (spectatee_status == -1 && newspectatee_status > 0) //before observing, now spectating
+                 || (spectatee_status > 0 && newspectatee_status > 0 && spectatee_status != newspectatee_status) //changed spectated player
+               )
+                       prev_p_health = -1;
+               else if(spectatee_status && !newspectatee_status) //before observing/spectating, now playing
+                       prev_health = -1;
+       }
+       spectatee_status = newspectatee_status;
+       // we could get rid of spectatee_status, and derive it from player_localentnum and player_localnum
+ }
+ void Ent_Nagger()
+ {
+     int i, j, b, f;
+     int nags = ReadByte(); // NAGS NAGS NAGS NAGS NAGS NAGS NADZ NAGS NAGS NAGS
+       if(!(nags & 4))
+       {
+               if(vote_called_vote)
+                       strunzone(vote_called_vote);
+               vote_called_vote = string_null;
+               vote_active = 0;
+       }
+       else
+       {
+               vote_active = 1;
+       }
+       if(nags & 64)
+       {
+               vote_yescount = ReadByte();
+               vote_nocount = ReadByte();
+               vote_needed = ReadByte();
+               vote_highlighted = ReadChar();
+       }
+       if(nags & 128)
+       {
+               if(vote_called_vote)
+                       strunzone(vote_called_vote);
+               vote_called_vote = strzone(ColorTranslateRGB(ReadString()));
+       }
+       if(nags & 1)
+       {
+               for(j = 0; j < maxclients; ++j)
+                       if(playerslots[j])
+                               playerslots[j].ready = 1;
+               for(i = 1; i <= maxclients; i += 8)
+               {
+                       f = ReadByte();
+                       for(j = i-1, b = 1; b < 256; b *= 2, ++j)
+                               if (!(f & b))
+                                       if(playerslots[j])
+                                               playerslots[j].ready = 0;
+               }
+       }
+       ready_waiting = (nags & 1);
+       ready_waiting_for_me = (nags & 2);
+       vote_waiting = (nags & 4);
+       vote_waiting_for_me = (nags & 8);
+       warmup_stage = (nags & 16);
+ }
+ void Ent_EliminatedPlayers()
+ {
+     int i, j, b, f;
+     int sf = ReadByte();
+       if(sf & 1)
+       {
+               for(j = 0; j < maxclients; ++j)
+                       if(playerslots[j])
+                               playerslots[j].eliminated = 1;
+               for(i = 1; i <= maxclients; i += 8)
+               {
+                       f = ReadByte();
+                       for(j = i-1, b = 1; b < 256; b *= 2, ++j)
+                               if (!(f & b))
+                                       if(playerslots[j])
+                                               playerslots[j].eliminated = 0;
+               }
+       }
+ }
+ void Ent_RandomSeed()
+ {
+       float s;
+       prandom_debug();
+       s = ReadShort();
+       psrandom(s);
+ }
+ void Ent_ReadAccuracy(void)
+ {
+     int f, w;
+     int sf = ReadInt24_t();
+       if(sf == 0)
+       {
+               for(w = 0; w <= WEP_LAST - WEP_FIRST; ++w)
+                       weapon_accuracy[w] = -1;
+               return;
+       }
+       for(w = 0, f = 1; w <= WEP_LAST - WEP_FIRST; ++w)
+       {
+               if(sf & f)
+               {
+             int b = ReadByte();
+                       if(b == 0)
+                               weapon_accuracy[w] = -1;
+                       else if(b == 255)
+                               weapon_accuracy[w] = 1.0; // no better error handling yet, sorry
+                       else
+                               weapon_accuracy[w] = (b - 1.0) / 100.0;
+               }
+               if(f == 0x800000)
+                       f = 1;
+               else
+                       f *= 2;
+       }
+ }
+ void Spawn_Draw(void)
+ {
+       pointparticles(self.cnt, self.origin + '0 0 28', '0 0 2', bound(0, frametime, 0.1));
+ }
+ void Ent_ReadSpawnPoint(float is_new) // entity for spawnpoint
+ {
+       float teamnum = (ReadByte() - 1);
+       vector spn_origin;
+       spn_origin.x = ReadShort();
+       spn_origin.y = ReadShort();
+       spn_origin.z = ReadShort();
+       if(is_new)
+       {
+               self.origin = spn_origin;
+               setsize(self, PL_MIN, PL_MAX);
+               droptofloor();
+               /*if(autocvar_cl_spawn_point_model) // needs a model first
+               {
+                       self.mdl = "models/spawnpoint.md3";
+                       self.colormod = Team_ColorRGB(teamnum);
+                       precache_model(self.mdl);
+                       setmodel(self, self.mdl);
+                       self.drawmask = MASK_NORMAL;
+                       //self.movetype = MOVETYPE_NOCLIP;
+                       //self.draw = Spawn_Draw;
+               }*/
+               if(autocvar_cl_spawn_point_particles)
+               {
+                       if((serverflags & SERVERFLAG_TEAMPLAY))
+                       {
+                               switch(teamnum)
+                               {
+                                       case NUM_TEAM_1: self.cnt = particleeffectnum("spawn_point_red"); break;
+                                       case NUM_TEAM_2: self.cnt = particleeffectnum("spawn_point_blue"); break;
+                                       case NUM_TEAM_3: self.cnt = particleeffectnum("spawn_point_yellow"); break;
+                                       case NUM_TEAM_4: self.cnt = particleeffectnum("spawn_point_pink"); break;
+                                       default: self.cnt = particleeffectnum("spawn_point_neutral"); break;
+                               }
+                       }
+                       else { self.cnt = particleeffectnum("spawn_point_neutral"); }
+                       self.draw = Spawn_Draw;
+               }
+       }
+       //printf("Ent_ReadSpawnPoint(is_new = %d); origin = %s, team = %d, effect = %d\n", is_new, vtos(self.origin), teamnum, self.cnt);
+ }
+ void Ent_ReadSpawnEvent(float is_new)
+ {
+       // If entnum is 0, ONLY do the local spawn actions
+       // this way the server can disable the sending of
+       // spawn origin or such to clients if wanted.
+       float entnum = ReadByte();
+       if(entnum)
+       {
+               self.origin_x = ReadShort();
+               self.origin_y = ReadShort();
+               self.origin_z = ReadShort();
+               if(is_new)
+               {
+                       float teamnum = GetPlayerColor(entnum - 1);
+                       if(autocvar_cl_spawn_event_particles)
+                       {
+                               switch(teamnum)
+                               {
+                                       case NUM_TEAM_1: pointparticles(particleeffectnum("spawn_event_red"), self.origin, '0 0 0', 1); break;
+                                       case NUM_TEAM_2: pointparticles(particleeffectnum("spawn_event_blue"), self.origin, '0 0 0', 1); break;
+                                       case NUM_TEAM_3: pointparticles(particleeffectnum("spawn_event_yellow"), self.origin, '0 0 0', 1); break;
+                                       case NUM_TEAM_4: pointparticles(particleeffectnum("spawn_event_pink"), self.origin, '0 0 0', 1); break;
+                                       default: pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); break;
+                               }
+                       }
+                       if(autocvar_cl_spawn_event_sound)
+                       {
+                               sound(self, CH_TRIGGER, "misc/spawn.wav", VOL_BASE, ATTEN_NORM);
+                       }
+               }
+       }
+       // local spawn actions
+       if(is_new && (!entnum || (entnum == player_localentnum)))
+       {
+               zoomin_effect = 1;
+               current_viewzoom = (1 / bound(1, autocvar_cl_spawnzoom_factor, 16));
+               if(autocvar_cl_unpress_zoom_on_spawn)
+               {
+                       localcmd("-zoom\n");
+                       button_zoom = false;
+               }
+       }
+       //printf("Ent_ReadSpawnEvent(is_new = %d); origin = %s, entnum = %d, localentnum = %d\n", is_new, vtos(self.origin), entnum, player_localentnum);
+ }
+ // CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured.
+ // The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS.
+ void Ent_RadarLink();
+ void Ent_Init();
+ void Ent_ScoresInfo();
+ void CSQC_Ent_Update(float bIsNewEntity)
+ {
+       float t;
+       float savetime;
+       t = ReadByte();
+       if(autocvar_developer_csqcentities)
+               printf("CSQC_Ent_Update(%d) with self=%i self.entnum=%d self.enttype=%d t=%d\n", bIsNewEntity, self, self.entnum, self.enttype, t);
+       // set up the "time" global for received entities to be correct for interpolation purposes
+       savetime = time;
+       if(servertime)
+       {
+               time = servertime;
+       }
+       else
+       {
+               serverprevtime = time;
+               serverdeltatime = getstatf(STAT_MOVEVARS_TICRATE) * getstatf(STAT_MOVEVARS_TIMESCALE);
+               time = serverprevtime + serverdeltatime;
+       }
+ #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED
+       if(self.enttype)
+       {
+               if(t != self.enttype || bIsNewEntity)
+               {
+                       //print("A CSQC entity changed its type!\n");
+                       printf("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n", num_for_edict(self), self.entnum, self.enttype, t);
+                       Ent_Remove();
+                       clearentity(self);
+                       bIsNewEntity = 1;
+               }
+       }
+       else
+       {
+               if(!bIsNewEntity)
+               {
+                       printf("A CSQC entity appeared out of nowhere! (edict: %d, server: %d, type: %d)\n", num_for_edict(self), self.entnum, t);
+                       bIsNewEntity = 1;
+               }
+       }
+ #endif
+       self.enttype = t;
+       switch(t)
+       {
+               case ENT_CLIENT_ENTCS: Ent_ReadEntCS(); break;
+               case ENT_CLIENT_SCORES: Ent_ReadPlayerScore(); break;
+               case ENT_CLIENT_TEAMSCORES: Ent_ReadTeamScore(); break;
+               case ENT_CLIENT_POINTPARTICLES: Ent_PointParticles(); break;
+               case ENT_CLIENT_RAINSNOW: Ent_RainOrSnow(); break;
+               case ENT_CLIENT_LASER: Ent_Laser(); break;
+               case ENT_CLIENT_NAGGER: Ent_Nagger(); break;
+               case ENT_CLIENT_ELIMINATEDPLAYERS: Ent_EliminatedPlayers(); break;
+               case ENT_CLIENT_WAYPOINT: Ent_WaypointSprite(); break;
+               case ENT_CLIENT_RADARLINK: Ent_RadarLink(); break;
+               case ENT_CLIENT_PROJECTILE: Ent_Projectile(); break;
+               case ENT_CLIENT_GIBSPLASH: Ent_GibSplash(bIsNewEntity); break;
+               case ENT_CLIENT_DAMAGEINFO: Ent_DamageInfo(bIsNewEntity); break;
+               case ENT_CLIENT_CASING: Ent_Casing(bIsNewEntity); break;
+               case ENT_CLIENT_INIT: Ent_Init(); break;
+               case ENT_CLIENT_SCORES_INFO: Ent_ScoresInfo(); break;
+               case ENT_CLIENT_MAPVOTE: Ent_MapVote(); break;
+               case ENT_CLIENT_CLIENTDATA: Ent_ClientData(); break;
+               case ENT_CLIENT_RANDOMSEED: Ent_RandomSeed(); break;
+               case ENT_CLIENT_WALL: Ent_Wall(); break;
+               case ENT_CLIENT_MODELEFFECT: Ent_ModelEffect(bIsNewEntity); break;
+               case ENT_CLIENT_TUBANOTE: Ent_TubaNote(bIsNewEntity); break;
+               case ENT_CLIENT_WARPZONE: WarpZone_Read(bIsNewEntity); break;
+               case ENT_CLIENT_WARPZONE_CAMERA: WarpZone_Camera_Read(bIsNewEntity); break;
+               case ENT_CLIENT_WARPZONE_TELEPORTED: WarpZone_Teleported_Read(bIsNewEntity); break;
+               case ENT_CLIENT_TRIGGER_MUSIC: Ent_ReadTriggerMusic(); break;
+               case ENT_CLIENT_HOOK: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_HOOK); break;
+               case ENT_CLIENT_ARC_BEAM: Ent_ReadArcBeam(bIsNewEntity); break;
+               case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break;
+               case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break;
+               case ENT_CLIENT_TURRET: ent_turret(); break;
+               case ENT_CLIENT_MODEL: CSQCModel_Read(bIsNewEntity); break;
+               case ENT_CLIENT_ITEM: ItemRead(bIsNewEntity); break;
+               case ENT_CLIENT_BUMBLE_RAYGUN: bumble_raygun_read(bIsNewEntity); break;
+               case ENT_CLIENT_SPAWNPOINT: Ent_ReadSpawnPoint(bIsNewEntity); break;
+               case ENT_CLIENT_SPAWNEVENT: Ent_ReadSpawnEvent(bIsNewEntity); break;
+               case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break;
+               case ENT_CLIENT_HEALING_ORB: ent_healer(); break;
+               case ENT_CLIENT_LADDER: ent_func_ladder(); break;
+               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;
++              case ENT_CLIENT_PLAT: ent_plat(); break;
++              case ENT_CLIENT_PLAT_TRIGGER: ent_plat_trigger(); break;
++              case ENT_CLIENT_SWAMP: ent_swamp(); break;
+               default:
+                       //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype));
+                       error(sprintf("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n", self.enttype, num_for_edict(self), self.classname));
+                       break;
+       }
+       time = savetime;
+ }
+ // Destructor, but does NOT deallocate the entity by calling remove(). Also
+ // used when an entity changes its type. For an entity that someone interacts
+ // with others, make sure it can no longer do so.
+ void Ent_Remove()
+ {
+       if(self.entremove)
+               self.entremove();
+       if(self.skeletonindex)
+       {
+               skel_delete(self.skeletonindex);
+               self.skeletonindex = 0;
+       }
+       if(self.snd_looping > 0)
+       {
+               sound(self, self.snd_looping, "misc/null.wav", VOL_BASE, autocvar_g_jetpack_attenuation);
+               self.snd_looping = 0;
+       }
+       self.enttype = 0;
+       self.classname = "";
+       self.draw = menu_sub_null;
+       self.entremove = menu_sub_null;
+       // TODO possibly set more stuff to defaults
+ }
+ // CSQC_Ent_Remove : Called when the server requests a SSQC / CSQC entity to be removed.  Essentially call remove(self) as well.
+ void CSQC_Ent_Remove()
+ {
+       if(autocvar_developer_csqcentities)
+               printf("CSQC_Ent_Remove() with self=%i self.entnum=%d self.enttype=%d\n", self, self.entnum, self.enttype);
+       if(wasfreed(self))
+       {
+               print("WARNING: CSQC_Ent_Remove called for already removed entity. Packet loss?\n");
+               return;
+       }
+       if(self.enttype)
+               Ent_Remove();
+       remove(self);
+ }
+ void Gamemode_Init()
+ {
+       if (!isdemo())
+       {
+               if(!(calledhooks & HOOK_START))
+                       localcmd("\n_cl_hook_gamestart ", MapInfo_Type_ToString(gametype), "\n");
+               calledhooks |= HOOK_START;
+       }
+ }
+ // CSQC_Parse_StuffCmd : Provides the stuffcmd string in the first parameter that the server provided.  To execute standard behavior, simply execute localcmd with the string.
+ void CSQC_Parse_StuffCmd(string strMessage)
+ {
+       if(autocvar_developer_csqcentities)
+               printf("CSQC_Parse_StuffCmd(\"%s\")\n", strMessage);
+       localcmd(strMessage);
+ }
+ // CSQC_Parse_Print : Provides the print string in the first parameter that the server provided.  To execute standard behavior, simply execute print with the string.
+ void CSQC_Parse_Print(string strMessage)
+ {
+       if(autocvar_developer_csqcentities)
+               printf("CSQC_Parse_Print(\"%s\")\n", strMessage);
+       print(ColorTranslateRGB(strMessage));
+ }
+ // CSQC_Parse_CenterPrint : Provides the centerprint_hud string in the first parameter that the server provided.
+ void CSQC_Parse_CenterPrint(string strMessage)
+ {
+       if(autocvar_developer_csqcentities)
+               printf("CSQC_Parse_CenterPrint(\"%s\")\n", strMessage);
+       centerprint_hud(strMessage);
+ }
+ string notranslate_fogcmd1 = "\nfog ";
+ string notranslate_fogcmd2 = "\nr_fog_exp2 0\nr_drawfog 1\n";
+ void Fog_Force()
+ {
+       // TODO somehow thwart prvm_globalset client ...
+       if(autocvar_cl_orthoview && autocvar_cl_orthoview_nofog)
+               { localcmd("\nr_drawfog 0\n"); }
+       else if(forcefog != "")
+               { localcmd(strcat(notranslate_fogcmd1, forcefog, notranslate_fogcmd2)); }
+ }
+ void Gamemode_Init();
+ void Ent_ScoresInfo()
+ {
+     int i;
+       self.classname = "ent_client_scores_info";
+       gametype = ReadInt24_t();
+       HUD_ModIcons_SetFunc();
+       for(i = 0; i < MAX_SCORE; ++i)
+       {
+               if(scores_label[i])
+                       strunzone(scores_label[i]);
+               scores_label[i] = strzone(ReadString());
+               scores_flags[i] = ReadByte();
+       }
+       for(i = 0; i < MAX_TEAMSCORE; ++i)
+       {
+               if(teamscores_label[i])
+                       strunzone(teamscores_label[i]);
+               teamscores_label[i] = strzone(ReadString());
+               teamscores_flags[i] = ReadByte();
+       }
+       HUD_InitScores();
+       Gamemode_Init();
+ }
+ void Ent_Init()
+ {
+       self.classname = "ent_client_init";
+       nb_pb_period = ReadByte() / 32; //Accuracy of 1/32th
+       hook_shotorigin[0] = decompressShotOrigin(ReadInt24_t());
+       hook_shotorigin[1] = decompressShotOrigin(ReadInt24_t());
+       hook_shotorigin[2] = decompressShotOrigin(ReadInt24_t());
+       hook_shotorigin[3] = decompressShotOrigin(ReadInt24_t());
+       arc_shotorigin[0] = decompressShotOrigin(ReadInt24_t());
+       arc_shotorigin[1] = decompressShotOrigin(ReadInt24_t());
+       arc_shotorigin[2] = decompressShotOrigin(ReadInt24_t());
+       arc_shotorigin[3] = decompressShotOrigin(ReadInt24_t());
+       if(forcefog)
+               strunzone(forcefog);
+       forcefog = strzone(ReadString());
+       armorblockpercent = ReadByte() / 255.0;
+       g_balance_mortar_bouncefactor = ReadCoord();
+       g_balance_mortar_bouncestop = ReadCoord();
+       g_balance_electro_secondary_bouncefactor = ReadCoord();
+       g_balance_electro_secondary_bouncestop = ReadCoord();
+       vortex_scope = !ReadByte();
+       rifle_scope = !ReadByte();
+       serverflags = ReadByte();
+       minelayer_maxmines = ReadByte();
+       hagar_maxrockets = ReadByte();
+       g_trueaim_minrange = ReadCoord();
+       g_balance_porto_secondary = ReadByte();
+       if(!postinit)
+               PostInit();
+ }
+ void Net_ReadRace()
+ {
+       float b;
+       b = ReadByte();
+       switch(b)
+       {
+               case RACE_NET_CHECKPOINT_HIT_QUALIFYING:
+                       race_checkpoint = ReadByte();
+                       race_time = ReadInt24_t();
+                       race_previousbesttime = ReadInt24_t();
+                       if(race_previousbestname)
+                               strunzone(race_previousbestname);
+                       race_previousbestname = strzone(ColorTranslateRGB(ReadString()));
+                       race_checkpointtime = time;
+                       if(race_checkpoint == 0 || race_checkpoint == 254)
+                       {
+                               race_penaltyaccumulator = 0;
+                               race_laptime = time; // valid
+                       }
+                       break;
+               case RACE_NET_CHECKPOINT_CLEAR:
+                       race_laptime = 0;
+                       race_checkpointtime = 0;
+                       break;
+               case RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING:
+                       race_laptime = ReadCoord();
+                       race_checkpointtime = -99999;
+                       // fall through
+               case RACE_NET_CHECKPOINT_NEXT_QUALIFYING:
+                       race_nextcheckpoint = ReadByte();
+                       race_nextbesttime = ReadInt24_t();
+                       if(race_nextbestname)
+                               strunzone(race_nextbestname);
+                       race_nextbestname = strzone(ColorTranslateRGB(ReadString()));
+                       break;
+               case RACE_NET_CHECKPOINT_HIT_RACE:
+                       race_mycheckpoint = ReadByte();
+                       race_mycheckpointtime = time;
+                       race_mycheckpointdelta = ReadInt24_t();
+                       race_mycheckpointlapsdelta = ReadByte();
+                       if(race_mycheckpointlapsdelta >= 128)
+                               race_mycheckpointlapsdelta -= 256;
+                       if(race_mycheckpointenemy)
+                               strunzone(race_mycheckpointenemy);
+                       race_mycheckpointenemy = strzone(ColorTranslateRGB(ReadString()));
+                       break;
+               case RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT:
+                       race_othercheckpoint = ReadByte();
+                       race_othercheckpointtime = time;
+                       race_othercheckpointdelta = ReadInt24_t();
+                       race_othercheckpointlapsdelta = ReadByte();
+                       if(race_othercheckpointlapsdelta >= 128)
+                               race_othercheckpointlapsdelta -= 256;
+                       if(race_othercheckpointenemy)
+                               strunzone(race_othercheckpointenemy);
+                       race_othercheckpointenemy = strzone(ColorTranslateRGB(ReadString()));
+                       break;
+               case RACE_NET_PENALTY_RACE:
+                       race_penaltyeventtime = time;
+                       race_penaltytime = ReadShort();
+                       //race_penaltyaccumulator += race_penaltytime;
+                       if(race_penaltyreason)
+                               strunzone(race_penaltyreason);
+                       race_penaltyreason = strzone(ReadString());
+                       break;
+               case RACE_NET_PENALTY_QUALIFYING:
+                       race_penaltyeventtime = time;
+                       race_penaltytime = ReadShort();
+                       race_penaltyaccumulator += race_penaltytime;
+                       if(race_penaltyreason)
+                               strunzone(race_penaltyreason);
+                       race_penaltyreason = strzone(ReadString());
+                       break;
+               case RACE_NET_SERVER_RECORD:
+                       race_server_record = ReadInt24_t();
+                       break;
+               case RACE_NET_SPEED_AWARD:
+                       race_speedaward = ReadInt24_t();
+                       if(race_speedaward_holder)
+                               strunzone(race_speedaward_holder);
+                       race_speedaward_holder = strzone(ReadString());
+                       break;
+               case RACE_NET_SPEED_AWARD_BEST:
+                       race_speedaward_alltimebest = ReadInt24_t();
+                       if(race_speedaward_alltimebest_holder)
+                               strunzone(race_speedaward_alltimebest_holder);
+                       race_speedaward_alltimebest_holder = strzone(ReadString());
+                       break;
+               case RACE_NET_SERVER_RANKINGS:
+                       float prevpos, del;
+             int pos = ReadShort();
+                       prevpos = ReadShort();
+                       del = ReadShort();
+                       // move other rankings out of the way
+             int i;
+                       if (prevpos) {
+                               for (i=prevpos-1;i>pos-1;--i) {
+                                       grecordtime[i] = grecordtime[i-1];
+                                       if(grecordholder[i])
+                                               strunzone(grecordholder[i]);
+                                       grecordholder[i] = strzone(grecordholder[i-1]);
+                               }
+                       } else if (del) { // a record has been deleted by the admin
+                               for (i=pos-1; i<= RANKINGS_CNT-1; ++i) {
+                                       if (i == RANKINGS_CNT-1) { // clear out last record
+                                               grecordtime[i] = 0;
+                                               if (grecordholder[i])
+                                                       strunzone(grecordholder[i]);
+                                               grecordholder[i] = string_null;
+                                       }
+                                       else {
+                                               grecordtime[i] = grecordtime[i+1];
+                                               if (grecordholder[i])
+                                                       strunzone(grecordholder[i]);
+                                               grecordholder[i] = strzone(grecordholder[i+1]);
+                                       }
+                               }
+                       } else { // player has no ranked record yet
+                               for (i=RANKINGS_CNT-1;i>pos-1;--i) {
+                                       grecordtime[i] = grecordtime[i-1];
+                                       if(grecordholder[i])
+                                               strunzone(grecordholder[i]);
+                                       grecordholder[i] = strzone(grecordholder[i-1]);
+                               }
+                       }
+                       // store new ranking
+                       if(grecordholder[pos-1] != "")
+                               strunzone(grecordholder[pos-1]);
+                       grecordholder[pos-1] = strzone(ReadString());
+                       grecordtime[pos-1] = ReadInt24_t();
+                       if(grecordholder[pos-1] == GetPlayerName(player_localnum))
+                               race_myrank = pos;
+                       break;
+               case RACE_NET_SERVER_STATUS:
+                       race_status = ReadShort();
+                       if(race_status_name)
+                               strunzone(race_status_name);
+                       race_status_name = strzone(ReadString());
+       }
+ }
+ void Net_TeamNagger()
+ {
+       teamnagger = 1;
+ }
+ void Net_ReadPingPLReport()
+ {
+       int e, pi, pl, ml;
+       e = ReadByte();
+       pi = ReadShort();
+       pl = ReadByte();
+       ml = ReadByte();
+       if (!(playerslots[e]))
+               return;
+       playerslots[e].ping = pi;
+       playerslots[e].ping_packetloss = pl / 255.0;
+       playerslots[e].ping_movementloss = ml / 255.0;
+ }
+ void Net_WeaponComplain()
+ {
+       complain_weapon = ReadByte();
+       if(complain_weapon_name)
+               strunzone(complain_weapon_name);
+       complain_weapon_name = strzone(WEP_NAME(complain_weapon));
+       complain_weapon_type = ReadByte();
+       complain_weapon_time = time;
+       weapontime = time; // ping the weapon panel
+       switch(complain_weapon_type)
+       {
+               case 0: Local_Notification(MSG_MULTI, ITEM_WEAPON_NOAMMO, complain_weapon); break;
+               case 1: Local_Notification(MSG_MULTI, ITEM_WEAPON_DONTHAVE, complain_weapon); break;
+               default: Local_Notification(MSG_MULTI, ITEM_WEAPON_UNAVAILABLE, complain_weapon); break;
+       }
+ }
+ // CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer.
+ // You must ALWAYS first acquire the temporary ID, which is sent as a byte.
+ // Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event.
+ float CSQC_Parse_TempEntity()
+ {
+       float bHandled;
+               bHandled  = true;
+       // Acquire TE ID
+       float nTEID;
+               nTEID = ReadByte();
+       if(autocvar_developer_csqcentities)
+               printf("CSQC_Parse_TempEntity() with nTEID=%d\n", nTEID);
+               // NOTE: Could just do return instead of break...
+       switch(nTEID)
+       {
+               case TE_CSQC_TARGET_MUSIC:
+                       Net_TargetMusic();
+                       bHandled = true;
+                       break;
+               case TE_CSQC_PICTURE:
+                       Net_MapVote_Picture();
+                       bHandled = true;
+                       break;
+               case TE_CSQC_RACE:
+                       Net_ReadRace();
+                       bHandled = true;
+                       break;
+               case TE_CSQC_VORTEXBEAMPARTICLE:
+                       Net_ReadVortexBeamParticle();
+                       bHandled = true;
+                       break;
+               case TE_CSQC_TEAMNAGGER:
+                       Net_TeamNagger();
+                       bHandled = true;
+                       break;
+               case TE_CSQC_ARC:
+                       Net_ReadArc();
+                       bHandled = true;
+                       break;
+               case TE_CSQC_PINGPLREPORT:
+                       Net_ReadPingPLReport();
+                       bHandled = true;
+                       break;
+               case TE_CSQC_WEAPONCOMPLAIN:
+                       Net_WeaponComplain();
+                       bHandled = true;
+                       break;
+               case TE_CSQC_VEHICLESETUP:
+                       Net_VehicleSetup();
+                       bHandled = true;
+                       break;
+               case TE_CSQC_SVNOTICE:
+                       cl_notice_read();
+                       bHandled = true;
+                       break;
+               case TE_CSQC_SHOCKWAVEPARTICLE:
+                       Net_ReadShockwaveParticle();
+                       bHandled = true;
+                       break;
+               default:
+                       // No special logic for this temporary entity; return 0 so the engine can handle it
+                       bHandled = false;
+                       break;
+       }
+       return bHandled;
+ }
+ string getcommandkey(string text, string command)
+ {
+       string keys;
+       float n, j, k, l = 0;
+       if (!autocvar_hud_showbinds)
+               return text;
+       keys = db_get(binddb, command);
+       if (keys == "")
+       {
+               n = tokenize(findkeysforcommand(command, 0)); // uses '...' strings
+               for(j = 0; j < n; ++j)
+               {
+                       k = stof(argv(j));
+                       if(k != -1)
+                       {
+                               if ("" == keys)
+                                       keys = keynumtostring(k);
+                               else
+                                       keys = strcat(keys, ", ", keynumtostring(k));
+                               ++l;
+                               if (autocvar_hud_showbinds_limit > 0 && autocvar_hud_showbinds_limit <= l)
+                                       break;
+                       }
+               }
+               if (keys == "")
+                       keys = "NO_KEY";
+               db_put(binddb, command, keys);
+       }
+       if (keys == "NO_KEY") {
+               if (autocvar_hud_showbinds > 1)
+                       return sprintf(_("%s (not bound)"), text);
+               else
+                       return text;
+       }
+       else if (autocvar_hud_showbinds > 1)
+               return sprintf("%s (%s)", text, keys);
+       else
+               return keys;
+ }
@@@ -117,26 -60,23 +60,23 @@@ weapons/projectile.qc // TOD
  
  ../common/monsters/monsters.qc
  
- ../common/physics.qh
- ../server/mutators/mutator_dodging.qc
+ ../common/weapons/weapons.qc // TODO
++../common/triggers/include.qc
++
+ ../csqcmodellib/cl_model.qc
+ ../csqcmodellib/cl_player.qc
+ ../csqcmodellib/interpolate.qc
+ ../server/movelib.qc
 -../server/t_halflife.qc
 -../server/t_items.qc
 -../server/t_jumppads.qc
 -../server/t_plats.qc
  ../server/mutators/mutator_multijump.qc
  
- ../common/nades.qc
- ../common/buffs.qc
- ../common/physics.qc
+ ../server/vehicles/bumblebee.qc
  
- ../common/triggers/include.qc
++../server/t_items.qc
 +
  ../warpzonelib/anglestransform.qc
- ../warpzonelib/mathlib.qc
- ../warpzonelib/common.qc
  ../warpzonelib/client.qc
- tturrets.qc
- player_skeleton.qc
- ../common/animdecide.qc
+ ../warpzonelib/common.qc
+ ../warpzonelib/mathlib.qc
@@@ -103,13 -56,13 +56,13 @@@ void drawhealthbar(vector org, float ro
        up = rotate(up, rot);
  
        owidth = width + 2 * border;
-       o = o - up * (margin + border + theheight) + ri * (sz_x - owidth) * 0.5;
 -      o = o - up * (margin + border + height) + ri * (sz.x - owidth) * 0.5;
++      o = o - up * (margin + border + theheight) + ri * (sz.x - owidth) * 0.5;
  
        drawquad(o - up * border,                               ri * owidth,    up * border, "", rgb,  a,  f);
 -      drawquad(o + up * height,                               ri * owidth,    up * border, "", rgb,  a,  f);
 -      drawquad(o,                                             ri * border,    up * height, "", rgb,  a,  f);
 -      drawquad(o + ri * (owidth - border),                    ri * border,    up * height, "", rgb,  a,  f);
 -      drawquad(o + ri * (border + align * ((1 - h) * width)), ri * width * h, up * height, "", hrgb, ha, f);
 +      drawquad(o + up * theheight,                               ri * owidth,    up * border, "", rgb,  a,  f);
 +      drawquad(o,                                             ri * border,    up * theheight, "", rgb,  a,  f);
 +      drawquad(o + ri * (owidth - border),                    ri * border,    up * theheight, "", rgb,  a,  f);
 +      drawquad(o + ri * (border + align * ((1 - h) * width)), ri * width * h, up * theheight, "", hrgb, ha, f);
  }
  
  // returns location of sprite text
  // Revision 22: hook shot origin
  #define CSQC_REVISION 22
  
- const float AS_STRING = 1;
- const float AS_INT = 2;
- const float AS_FLOAT_TRUNCATED = 2;
- const float AS_FLOAT = 8;
- const float TE_CSQC_PICTURE = 100;
- const float TE_CSQC_RACE = 101;
- const float TE_CSQC_VORTEXBEAMPARTICLE = 103;
- const float TE_CSQC_ARC = 104;
- const float TE_CSQC_TEAMNAGGER = 105;
- const float TE_CSQC_PINGPLREPORT = 106;
- const float TE_CSQC_TARGET_MUSIC = 107;
- const float TE_CSQC_WEAPONCOMPLAIN = 108;
- const float TE_CSQC_VORTEX_SCOPE = 109;
- const float TE_CSQC_MINELAYER_MAXMINES = 110;
- const float TE_CSQC_HAGAR_MAXROCKETS = 111;
- const float TE_CSQC_VEHICLESETUP = 112;
- const float TE_CSQC_SVNOTICE = 113;
- const float TE_CSQC_SHOCKWAVEPARTICLE = 114;
- const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
- const float RACE_NET_CHECKPOINT_CLEAR = 1;
- const float RACE_NET_CHECKPOINT_NEXT_QUALIFYING = 2; // byte nextcheckpoint, short recordtime, string recordholder
- const float RACE_NET_CHECKPOINT_HIT_RACE = 3; // byte checkpoint, short delta, byte lapsdelta, string opponent
- const float RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT = 4; // byte checkpoint, short delta, byte lapsdelta, string opponent
- const float RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING = 5; // byte nextcheckpoint, float laptime, short recordtime, string recordholder
- const float RACE_NET_PENALTY_RACE = 6; // byte penaltytime, string reason
- const float RACE_NET_PENALTY_QUALIFYING = 7; // byte penaltytime, string reason
- const float RACE_NET_SERVER_RECORD = 8; // server record, sent to client
- const float RACE_NET_SPEED_AWARD = 9; // speed award, sent to client
- const float RACE_NET_SPEED_AWARD_BEST = 10; // all time best speed award, sent to client
- const float RACE_NET_SERVER_RANKINGS = 11;
- const float RACE_NET_SERVER_STATUS = 12;
- const float RANKINGS_CNT = 15;
- const float ENT_CLIENT = 0;
- const float ENT_CLIENT_DEAD = 1;
- const float ENT_CLIENT_ENTCS = 2;
- const float ENT_CLIENT_SCORES_INFO = 3;
- const float ENT_CLIENT_SCORES = 4;
- const float ENT_CLIENT_TEAMSCORES = 5;
- const float ENT_CLIENT_POINTPARTICLES = 6;
- const float ENT_CLIENT_RAINSNOW = 7;
- const float ENT_CLIENT_LASER = 8;
- const float ENT_CLIENT_NAGGER = 9; // flags [votecalledvote]
- const float ENT_CLIENT_WAYPOINT = 10; // flags origin [team displayrule] [spritename] [spritename2] [spritename3] [lifetime maxdistance hideable]
- const float ENT_CLIENT_RADARLINK = 11; // flags [startorigin] [endorigin] [startcolor+16*endcolor]
- const float ENT_CLIENT_PROJECTILE = 12;
- const float ENT_CLIENT_GIBSPLASH = 13;
- const float ENT_CLIENT_DAMAGEINFO = 14;
- const float ENT_CLIENT_CASING = 15;
- const float ENT_CLIENT_INIT = 16;
- const float ENT_CLIENT_MAPVOTE = 17;
- const float ENT_CLIENT_CLIENTDATA = 18;
- const float ENT_CLIENT_RANDOMSEED = 19;
- const float ENT_CLIENT_WALL = 20;
- const float ENT_CLIENT_SPIDERBOT = 21;
- const float ENT_CLIENT_MODELEFFECT = 22;
- const float ENT_CLIENT_TUBANOTE = 23;
- const float ENT_CLIENT_WARPZONE = 24;
- const float ENT_CLIENT_WARPZONE_CAMERA = 25;
- const float ENT_CLIENT_TRIGGER_MUSIC = 26;
- const float ENT_CLIENT_HOOK = 27;
- const float ENT_CLIENT_ARC_BEAM = 29; // WEAPONTODO: fix numbers
- const float ENT_CLIENT_ACCURACY = 30;
- const float ENT_CLIENT_SHOWNAMES = 31;
- const float ENT_CLIENT_WARPZONE_TELEPORTED = 32;
- const float ENT_CLIENT_MODEL = 33;
- const float ENT_CLIENT_ITEM = 34;
- const float ENT_CLIENT_BUMBLE_RAYGUN = 35;
- const float ENT_CLIENT_SPAWNPOINT = 36;
- const float ENT_CLIENT_SPAWNEVENT = 37;
- const float ENT_CLIENT_NOTIFICATION = 38;
- const float ENT_CLIENT_ELIMINATEDPLAYERS = 39;
- const float ENT_CLIENT_TURRET = 40;
- const float ENT_CLIENT_AUXILIARYXHAIR = 50;
- const float ENT_CLIENT_VEHICLE = 60;
- 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_PLAT = 67;
- const float ENT_CLIENT_PLAT_TRIGGER = 68;
- const float ENT_CLIENT_SWAMP = 69;
- const float ENT_CLIENT_HEALING_ORB = 80;
- const float SPRITERULE_DEFAULT = 0;
- const float SPRITERULE_TEAMPLAY = 1;
- const float RADARICON_NONE = 0;
- const float RADARICON_FLAG = 1;
- const float RADARICON_FLAGCARRIER = 1;
- const float RADARICON_HERE = 1; // TODO make these 3 and 4, and make images for them
- const float RADARICON_DANGER = 1;
- const float RADARICON_WAYPOINT = 1;
- const float RADARICON_HELPME = 1;
- const float RADARICON_CONTROLPOINT = 1;
- const float RADARICON_GENERATOR = 1;
- const float RADARICON_OBJECTIVE = 1;
- const float RADARICON_DOMPOINT = 1;
- const float RADARICON_POWERUP = 1;
- const float RADARICON_TAGGED = 1;
+ const int AS_STRING = 1;
+ const int AS_INT = 2;
+ const int AS_FLOAT_TRUNCATED = 2;
+ const int AS_FLOAT = 8;
+ const int TE_CSQC_PICTURE = 100;
+ const int TE_CSQC_RACE = 101;
+ const int TE_CSQC_VORTEXBEAMPARTICLE = 103;
+ const int TE_CSQC_ARC = 104;
+ const int TE_CSQC_TEAMNAGGER = 105;
+ const int TE_CSQC_PINGPLREPORT = 106;
+ const int TE_CSQC_TARGET_MUSIC = 107;
+ const int TE_CSQC_WEAPONCOMPLAIN = 108;
+ const int TE_CSQC_VORTEX_SCOPE = 109;
+ const int TE_CSQC_MINELAYER_MAXMINES = 110;
+ const int TE_CSQC_HAGAR_MAXROCKETS = 111;
+ const int TE_CSQC_VEHICLESETUP = 112;
+ const int TE_CSQC_SVNOTICE = 113;
+ const int TE_CSQC_SHOCKWAVEPARTICLE = 114;
+ const int RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
+ const int RACE_NET_CHECKPOINT_CLEAR = 1;
+ const int RACE_NET_CHECKPOINT_NEXT_QUALIFYING = 2; // byte nextcheckpoint, short recordtime, string recordholder
+ const int RACE_NET_CHECKPOINT_HIT_RACE = 3; // byte checkpoint, short delta, byte lapsdelta, string opponent
+ const int RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT = 4; // byte checkpoint, short delta, byte lapsdelta, string opponent
+ const int RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING = 5; // byte nextcheckpoint, float laptime, short recordtime, string recordholder
+ const int RACE_NET_PENALTY_RACE = 6; // byte penaltytime, string reason
+ const int RACE_NET_PENALTY_QUALIFYING = 7; // byte penaltytime, string reason
+ const int RACE_NET_SERVER_RECORD = 8; // server record, sent to client
+ const int RACE_NET_SPEED_AWARD = 9; // speed award, sent to client
+ const int RACE_NET_SPEED_AWARD_BEST = 10; // all time best speed award, sent to client
+ const int RACE_NET_SERVER_RANKINGS = 11;
+ const int RACE_NET_SERVER_STATUS = 12;
+ const int RANKINGS_CNT = 15;
+ const int ENT_CLIENT = 0;
+ const int ENT_CLIENT_DEAD = 1;
+ const int ENT_CLIENT_ENTCS = 2;
+ const int ENT_CLIENT_SCORES_INFO = 3;
+ const int ENT_CLIENT_SCORES = 4;
+ const int ENT_CLIENT_TEAMSCORES = 5;
+ const int ENT_CLIENT_POINTPARTICLES = 6;
+ const int ENT_CLIENT_RAINSNOW = 7;
+ const int ENT_CLIENT_LASER = 8;
+ const int ENT_CLIENT_NAGGER = 9; // flags [votecalledvote]
+ const int ENT_CLIENT_WAYPOINT = 10; // flags origin [team displayrule] [spritename] [spritename2] [spritename3] [lifetime maxdistance hideable]
+ const int ENT_CLIENT_RADARLINK = 11; // flags [startorigin] [endorigin] [startcolor+16*endcolor]
+ const int ENT_CLIENT_PROJECTILE = 12;
+ const int ENT_CLIENT_GIBSPLASH = 13;
+ const int ENT_CLIENT_DAMAGEINFO = 14;
+ const int ENT_CLIENT_CASING = 15;
+ const int ENT_CLIENT_INIT = 16;
+ const int ENT_CLIENT_MAPVOTE = 17;
+ const int ENT_CLIENT_CLIENTDATA = 18;
+ const int ENT_CLIENT_RANDOMSEED = 19;
+ const int ENT_CLIENT_WALL = 20;
+ const int ENT_CLIENT_SPIDERBOT = 21;
+ const int ENT_CLIENT_MODELEFFECT = 22;
+ const int ENT_CLIENT_TUBANOTE = 23;
+ const int ENT_CLIENT_WARPZONE = 24;
+ const int ENT_CLIENT_WARPZONE_CAMERA = 25;
+ const int ENT_CLIENT_TRIGGER_MUSIC = 26;
+ const int ENT_CLIENT_HOOK = 27;
+ const int ENT_CLIENT_ARC_BEAM = 29; // WEAPONTODO: fix numbers
+ const int ENT_CLIENT_ACCURACY = 30;
+ const int ENT_CLIENT_SHOWNAMES = 31;
+ const int ENT_CLIENT_WARPZONE_TELEPORTED = 32;
+ const int ENT_CLIENT_MODEL = 33;
+ const int ENT_CLIENT_ITEM = 34;
+ const int ENT_CLIENT_BUMBLE_RAYGUN = 35;
+ const int ENT_CLIENT_SPAWNPOINT = 36;
+ const int ENT_CLIENT_SPAWNEVENT = 37;
+ const int ENT_CLIENT_NOTIFICATION = 38;
+ const int ENT_CLIENT_ELIMINATEDPLAYERS = 39;
+ const int ENT_CLIENT_TURRET = 40;
+ const int ENT_CLIENT_AUXILIARYXHAIR = 50;
+ const int ENT_CLIENT_VEHICLE = 60;
+ const int ENT_CLIENT_LADDER = 61;
+ const int ENT_CLIENT_TRIGGER_PUSH = 62;
+ const int ENT_CLIENT_TARGET_PUSH = 63;
+ const int ENT_CLIENT_CONVEYOR = 64;
++const int ENT_CLIENT_DOOR = 65;
++const int ENT_CLIENT_DOOR_TRIGGER = 66;
++const int ENT_CLIENT_PLAT = 67;
++const int ENT_CLIENT_PLAT_TRIGGER = 68;
++const int ENT_CLIENT_SWAMP = 69;
+ const int ENT_CLIENT_HEALING_ORB = 80;
+ const int SPRITERULE_DEFAULT = 0;
+ const int SPRITERULE_TEAMPLAY = 1;
+ const int RADARICON_NONE = 0;
+ const int RADARICON_FLAG = 1;
+ const int RADARICON_FLAGCARRIER = 1;
+ const int RADARICON_HERE = 1; // TODO make these 3 and 4, and make images for them
+ const int RADARICON_DANGER = 1;
+ const int RADARICON_WAYPOINT = 1;
+ const int RADARICON_HELPME = 1;
+ const int RADARICON_CONTROLPOINT = 1;
+ const int RADARICON_GENERATOR = 1;
+ const int RADARICON_OBJECTIVE = 1;
+ const int RADARICON_DOMPOINT = 1;
+ const int RADARICON_POWERUP = 1;
+ const int RADARICON_TAGGED = 1;
  
  ///////////////////////////
  // keys pressed
@@@ -1,3 -1,29 +1,30 @@@
+ #if defined(CSQC)
+ #elif defined(MENUQC)
+ #elif defined(SVQC)
+       #include "../../dpdefs/progsdefs.qh"
+     #include "../../dpdefs/dpextensions.qh"
+     #include "../../warpzonelib/common.qh"
+     #include "../constants.qh"
+     #include "../teams.qh"
+     #include "../util.qh"
+     #include "monsters.qh"
+     #include "sv_monsters.qh"
+     #include "../weapons/weapons.qh"
+     #include "../../server/autocvars.qh"
+     #include "../../server/defs.qh"
+     #include "../deathtypes.qh"
+     #include "../../server/mutators/mutators_include.qh"
+     #include "../../server/tturrets/include/turrets_early.qh"
+     #include "../../server/vehicles/vehicles_def.qh"
+     #include "../../server/campaign.qh"
+     #include "../../server/command/common.qh"
+     #include "../../server/command/cmd.qh"
++      #include "../triggers/triggers.qh"
+     #include "../../csqcmodellib/sv_model.qh"
+     #include "../../server/round_handler.qh"
+     #include "../../server/tturrets/include/turrets.qh"
+ #endif
  // =========================
  //    SVQC Monster Properties
  // =========================
Simple merge
@@@ -1,46 -1,6 +1,8 @@@
- .float race_penalty;
+ #include "physics.qh"
++#include "triggers/trigger/swamp.qh"
++#include "triggers/trigger/jumppads.qh"
  
- .float gravity;
- .float swamp_slowdown;
- .float lastflags;
- .float lastground;
- .float wasFlying;
- .float spectatorspeed;
- .vector movement_old;
- .float buttons_old;
- .vector v_angle_old;
- .string lastclassname;
- .float() PlayerPhysplug;
- float AdjustAirAccelQW(float accelqw, float factor);
- #ifdef CSQC
- .float watertype;
- #elif defined(SVQC)
- .float stat_sv_airaccel_qw;
- .float stat_sv_airstrafeaccel_qw;
- .float stat_sv_airspeedlimit_nonqw;
- .float stat_sv_maxspeed;
- .float stat_movement_highspeed;
- .float stat_sv_friction_on_land;
- .float stat_sv_friction_slick;
- .float stat_doublejump;
- .float stat_jumpspeedcap_min;
- .float stat_jumpspeedcap_max;
- .float stat_jumpspeedcap_disable_onramps;
- .float stat_jetpack_accel_side;
- .float stat_jetpack_accel_up;
- .float stat_jetpack_antigravity;
- .float stat_jetpack_fuel;
- .float stat_jetpack_maxspeed_up;
- .float stat_jetpack_maxspeed_side;
+ #ifdef SVQC
  
  void Physics_AddStats()
  {
@@@ -2,12 -5,34 +5,34 @@@
  
  .entity conveyor;
  
+ .float race_penalty;
+ .float gravity;
+ .float swamp_slowdown;
+ .float lastflags;
+ .float lastground;
+ .float wasFlying;
+ .float spectatorspeed;
+ .vector movement_old;
+ .float buttons_old;
+ .vector v_angle_old;
+ .string lastclassname;
+ .float() PlayerPhysplug;
+ float AdjustAirAccelQW(float accelqw, float factor);
  #ifdef CSQC
  
 -      #include "../server/t_jumppads.qh"
 -
+       float PM_multijump_checkjump();
+       void PM_multijump();
 -    .float speed;
 -    .float watertype;
 -    .float jumppadcount;
 -    .float ladder_time;
 -    .entity ladder_entity;
++
++      .float watertype;
++
 +// TODO
 +      #define IS_CLIENT(s)                                            (s).isplayermodel
 +      #define IS_PLAYER(s)                                            (s).isplayermodel
 +      #define isPushable(s)                                           (s).isplayermodel
  
        float player_multijump;
        float player_jumpheight;
index c3890d1,0000000..eac14a4
mode 100644,000000..100644
--- /dev/null
@@@ -1,288 -1,0 +1,288 @@@
- void func_breakable_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
 +#ifdef SVQC
++#include "../../../server/weapons/common.qh"
++
 +.entity sprite;
 +
 +.float dmg;
 +.float dmg_edge;
 +.float dmg_radius;
 +.float dmg_force;
 +.float debrismovetype;
 +.float debrissolid;
 +.vector debrisvelocity;
 +.vector debrisvelocityjitter;
 +.vector debrisavelocityjitter;
 +.float debristime;
 +.float debristimejitter;
 +.float debrisfadetime;
 +.float debrisdamageforcescale;
 +.float debrisskin;
 +
 +.string mdl_dead; // or "" to hide when broken
 +.string debris; // space separated list of debris models
 +// other fields:
 +//   mdl = particle effect name
 +//   count = particle effect multiplier
 +//   targetname = target to trigger to unbreak the model
 +//   target = targets to trigger when broken
 +//   health = amount of damage it can take
 +//   spawnflags:
 +//     1 = start disabled (needs to be triggered to activate)
 +//     2 = indicate damage
 +// notes:
 +//   for mdl_dead to work, origin must be set (using a common/origin brush).
 +//   Otherwise mdl_dead will be displayed at the map origin, and nobody would
 +//   want that!
 +
-       local   entity dbr;
-       dbr = spawn();
++void func_breakable_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
 +
 +//
 +// func_breakable
 +// - basically func_assault_destructible for general gameplay use
 +//
 +void LaunchDebris (string debrisname, vector force)
 +{
-                  + '1 0 0' * random() * (self.absmax_x - self.absmin_x)
-                  + '0 1 0' * random() * (self.absmax_y - self.absmin_y)
-                  + '0 0 1' * random() * (self.absmax_z - self.absmin_z));
++      entity dbr = spawn();
 +      setorigin(dbr, self.absmin
-       dbr.velocity_x = self.debrisvelocity_x + self.debrisvelocityjitter_x * crandom();
-       dbr.velocity_y = self.debrisvelocity_y + self.debrisvelocityjitter_y * crandom();
-       dbr.velocity_z = self.debrisvelocity_z + self.debrisvelocityjitter_z * crandom();
++                 + '1 0 0' * random() * (self.absmax.x - self.absmin.x)
++                 + '0 1 0' * random() * (self.absmax.y - self.absmin.y)
++                 + '0 0 1' * random() * (self.absmax.z - self.absmin.z));
 +      setmodel (dbr, debrisname );
 +      dbr.skin = self.debrisskin;
 +      dbr.colormap = self.colormap; // inherit team colors
 +      dbr.owner = self; // do not be affected by our own explosion
 +      dbr.movetype = self.debrismovetype;
 +      dbr.solid = self.debrissolid;
 +      if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out
 +              setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it
-       dbr.avelocity_x = random()*self.debrisavelocityjitter_x;
-       dbr.avelocity_y = random()*self.debrisavelocityjitter_y;
-       dbr.avelocity_z = random()*self.debrisavelocityjitter_z;
++      dbr.velocity_x = self.debrisvelocity.x + self.debrisvelocityjitter.x * crandom();
++      dbr.velocity_y = self.debrisvelocity.y + self.debrisvelocityjitter.y * crandom();
++      dbr.velocity_z = self.debrisvelocity.z + self.debrisvelocityjitter.z * crandom();
 +      self.velocity = self.velocity + force * self.debrisdamageforcescale;
-               
++      dbr.avelocity_x = random()*self.debrisavelocityjitter.x;
++      dbr.avelocity_y = random()*self.debrisavelocityjitter.y;
++      dbr.avelocity_z = random()*self.debrisavelocityjitter.z;
 +      dbr.damageforcescale = self.debrisdamageforcescale;
 +      if(dbr.damageforcescale)
 +              dbr.takedamage = DAMAGE_YES;
 +      SUB_SetFade(dbr, time + self.debristime + crandom() * self.debristimejitter, self.debrisfadetime);
 +}
 +
 +void func_breakable_colormod()
 +{
 +      float h;
 +      if (!(self.spawnflags & 2))
 +              return;
 +      h = self.health / self.max_health;
 +      if(h < 0.25)
 +              self.colormod = '1 0 0';
 +      else if(h <= 0.75)
 +              self.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);
 +      else
 +              self.colormod = '1 1 1';
-       float floor_z;
++
 +      CSQCMODEL_AUTOUPDATE();
 +}
 +
 +void func_breakable_look_destroyed()
 +{
-                       floor_z = self.absmin_z;
++      float floorZ;
 +
 +      if(self.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first
 +              self.dropped_origin = self.origin;
 +
 +      if(self.mdl_dead == "")
 +              self.model = "";
 +      else {
 +              if (self.origin == '0 0 0')     {       // probably no origin brush, so don't spawn in the middle of the map..
-                       self.origin_z = floor_z;
++                      floorZ = self.absmin.z;
 +                      setorigin(self,((self.absmax+self.absmin)*.5));
-       self.bot_attack = FALSE;
++                      self.origin_z = floorZ;
 +              }
 +              setmodel(self, self.mdl_dead);
 +      }
 +
 +      self.solid = SOLID_NOT;
 +}
 +
 +void func_breakable_look_restore()
 +{
 +      setmodel(self, self.mdl);
 +      if(self.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
 +              setorigin(self, self.dropped_origin);
 +      self.solid = SOLID_BSP;
 +}
 +
 +void func_breakable_behave_destroyed()
 +{
 +      self.health = self.max_health;
 +      self.takedamage = DAMAGE_NO;
-       self.bot_attack = TRUE;
++      self.bot_attack = false;
 +      self.event_damage = func_null;
 +      self.state = 1;
 +      func_breakable_colormod();
 +}
 +
 +void func_breakable_behave_restore()
 +{
 +      self.health = self.max_health;
 +      if(self.sprite)
 +      {
 +              WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
 +              WaypointSprite_UpdateHealth(self.sprite, self.health);
 +      }
 +      self.takedamage = DAMAGE_AIM;
-       
++      self.bot_attack = true;
 +      self.event_damage = func_breakable_damage;
 +      self.state = 0;
 +      self.nextthink = 0; // cancel auto respawn
 +      func_breakable_colormod();
 +}
 +
 +void func_breakable_destroyed()
 +{
 +      func_breakable_look_destroyed();
 +      func_breakable_behave_destroyed();
-       
++
 +      CSQCMODEL_AUTOUPDATE();
 +}
 +
 +void func_breakable_restore()
 +{
 +      func_breakable_look_restore();
 +      func_breakable_behave_restore();
- void func_breakable_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
++
 +      CSQCMODEL_AUTOUPDATE();
 +}
 +
 +vector debrisforce; // global, set before calling this
 +void func_breakable_destroy() {
 +      float n, i;
 +      string oldmsg;
 +
 +      activator = self.owner;
 +      self.owner = world; // set by W_PrepareExplosionByDamage
 +
 +      // now throw around the debris
 +      n = tokenize_console(self.debris);
 +      for(i = 0; i < n; ++i)
 +              LaunchDebris(argv(i), debrisforce);
 +
 +      func_breakable_destroyed();
 +
 +      if(self.noise)
 +              sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
 +
 +      if(self.dmg)
 +              RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, world, self.dmg_force, DEATH_HURTTRIGGER, world);
 +
 +      if(self.cnt)
 +              pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
 +
 +      if(self.respawntime)
 +      {
 +              self.think = func_breakable_restore;
 +              self.nextthink = time + self.respawntime + crandom() * self.respawntimejitter;
 +      }
 +
 +      oldmsg = self.message;
 +      self.message = "";
 +      SUB_UseTargets();
 +      self.message = oldmsg;
 +}
 +
-               
++void func_breakable_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
 +{
 +      if(self.state == 1)
 +              return;
 +      if(self.spawnflags & DOOR_NOSPLASH)
 +              if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
 +                      return;
 +      if(self.team)
 +              if(attacker.team == self.team)
 +                      return;
 +      self.health = self.health - damage;
 +      if(self.sprite)
 +      {
 +              WaypointSprite_Ping(self.sprite);
 +              WaypointSprite_UpdateHealth(self.sprite, self.health);
 +      }
 +      func_breakable_colormod();
 +
 +      if(self.health <= 0)
 +      {
 +              debrisforce = force;
 +              W_PrepareExplosionByDamage(attacker, func_breakable_destroy);
 +      }
 +}
 +
 +void func_breakable_reset()
 +{
 +      self.team = self.team_saved;
 +      func_breakable_look_restore();
 +      if(self.spawnflags & 1)
 +              func_breakable_behave_destroyed();
 +      else
 +              func_breakable_behave_restore();
-       
++
 +      CSQCMODEL_AUTOUPDATE();
 +}
 +
 +// destructible walls that can be used to trigger target_objective_decrease
 +void spawnfunc_func_breakable() {
 +      float n, i;
 +      if(!self.health)
 +              self.health = 100;
 +      self.max_health = self.health;
 +
 +      // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
 +      if(!self.debrismovetype) self.debrismovetype = MOVETYPE_BOUNCE;
 +      if(!self.debrissolid) self.debrissolid = SOLID_NOT;
 +      if(self.debrisvelocity == '0 0 0') self.debrisvelocity = '0 0 140';
 +      if(self.debrisvelocityjitter == '0 0 0') self.debrisvelocityjitter = '70 70 70';
 +      if(self.debrisavelocityjitter == '0 0 0') self.debrisavelocityjitter = '600 600 600';
 +      if(!self.debristime) self.debristime = 3.5;
 +      if(!self.debristimejitter) self.debristime = 2.5;
 +
 +      if(self.mdl != "")
 +              self.cnt = particleeffectnum(self.mdl);
 +      if(self.count == 0)
 +              self.count = 1;
 +
 +      if(self.message == "")
 +              self.message = "got too close to an explosion";
 +      if(self.message2 == "")
 +              self.message2 = "was pushed into an explosion by";
 +      if(!self.dmg_radius)
 +              self.dmg_radius = 150;
 +      if(!self.dmg_force)
 +              self.dmg_force = 200;
 +
 +      self.mdl = self.model;
 +      SetBrushEntityModel();
 +
 +      self.use = func_breakable_restore;
 +
 +      // precache all the models
 +      if (self.mdl_dead)
 +              precache_model(self.mdl_dead);
 +      n = tokenize_console(self.debris);
 +      for(i = 0; i < n; ++i)
 +              precache_model(argv(i));
 +      if(self.noise)
 +              precache_sound(self.noise);
 +
 +      self.team_saved = self.team;
 +      self.dropped_origin = self.origin;
 +
 +      self.reset = func_breakable_reset;
 +      func_breakable_reset();
++
 +      CSQCMODEL_AUTOINIT();
 +}
 +
 +// for use in maps with a "model" key set
 +void spawnfunc_misc_breakablemodel() {
 +      spawnfunc_func_breakable();
 +}
 +#endif
index 62b2d68,0000000..05f0fa0
mode 100644,000000..100644
--- /dev/null
@@@ -1,197 -1,0 +1,197 @@@
-       return TRUE;
 +void conveyor_think()
 +{
 +#ifdef CSQC
 +      // TODO: check if this is what is causing the glitchiness when switching between them
 +      float dt = time - self.move_time;
 +      self.move_time = time;
 +      if(dt <= 0) { return; }
 +#endif
 +      entity e;
 +
 +      // set myself as current conveyor where possible
 +      for(e = world; (e = findentity(e, conveyor, self)); )
 +              e.conveyor = world;
 +
 +      if(self.state)
 +      {
 +              for(e = findradius((self.absmin + self.absmax) * 0.5, vlen(self.absmax - self.absmin) * 0.5 + 1); e; e = e.chain)
 +                      if(!e.conveyor.state)
 +                              if(isPushable(e))
 +                              {
 +                                      vector emin = e.absmin;
 +                                      vector emax = e.absmax;
 +                                      if(self.solid == SOLID_BSP)
 +                                      {
 +                                              emin -= '1 1 1';
 +                                              emax += '1 1 1';
 +                                      }
 +                                      if(boxesoverlap(emin, emax, self.absmin, self.absmax)) // quick
 +                                              if(WarpZoneLib_BoxTouchesBrush(emin, emax, self, e)) // accurate
 +                                                      e.conveyor = self;
 +                              }
 +
 +              for(e = world; (e = findentity(e, conveyor, self)); )
 +              {
 +                      if(IS_CLIENT(e)) // doing it via velocity has quite some advantages
 +                              continue; // done in SV_PlayerPhysics   continue;
 +
 +                      setorigin(e, e.origin + self.movedir * PHYS_INPUT_FRAMETIME);
 +                      move_out_of_solid(e);
 +#ifdef SVQC
 +                      UpdateCSQCProjectile(e);
 +#endif
 +                      /*
 +                      // stupid conveyor code
 +                      tracebox(e.origin, e.mins, e.maxs, e.origin + self.movedir * sys_frametime, MOVE_NORMAL, e);
 +                      if(trace_fraction > 0)
 +                              setorigin(e, trace_endpos);
 +                      */
 +              }
 +      }
 +
 +#ifdef SVQC
 +      self.nextthink = time;
 +#endif
 +}
 +
 +#ifdef SVQC
 +
 +void conveyor_use()
 +{
 +      self.state = !self.state;
 +
 +      self.SendFlags |= 2;
 +}
 +
 +void conveyor_reset()
 +{
 +      self.state = (self.spawnflags & 1);
 +
 +      self.SendFlags |= 2;
 +}
 +
 +float conveyor_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_CONVEYOR);
 +      WriteByte(MSG_ENTITY, sf);
 +
 +      if(sf & 1)
 +      {
 +              WriteByte(MSG_ENTITY, self.warpzone_isboxy);
 +              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);
 +
 +              WriteByte(MSG_ENTITY, self.speed);
 +              WriteByte(MSG_ENTITY, self.state);
 +
 +              WriteString(MSG_ENTITY, self.targetname);
 +              WriteString(MSG_ENTITY, self.target);
 +      }
 +
 +      if(sf & 2)
 +              WriteByte(MSG_ENTITY, self.state);
 +
-       Net_LinkEntity(self, 0, FALSE, conveyor_send);
++      return true;
 +}
 +
 +void conveyor_init()
 +{
 +      if (!self.speed)
 +              self.speed = 200;
 +      self.movedir = self.movedir * self.speed;
 +      self.think = conveyor_think;
 +      self.nextthink = time;
 +      IFTARGETED
 +      {
 +              self.use = conveyor_use;
 +              self.reset = conveyor_reset;
 +              conveyor_reset();
 +      }
 +      else
 +              self.state = 1;
 +
 +      FixSize(self);
 +
++      Net_LinkEntity(self, 0, false, conveyor_send);
 +
 +      self.SendFlags |= 1;
 +}
 +
 +void spawnfunc_trigger_conveyor()
 +{
 +      SetMovedir();
 +      EXACTTRIGGER_INIT;
 +      conveyor_init();
 +}
 +
 +void spawnfunc_func_conveyor()
 +{
 +      SetMovedir();
 +      InitMovingBrushTrigger();
 +      self.movetype = MOVETYPE_NONE;
 +      conveyor_init();
 +}
 +
 +#elif defined(CSQC)
 +
 +void conveyor_init()
 +{
 +      self.draw = conveyor_think;
 +      self.drawmask = MASK_NORMAL;
 +
 +      self.movetype = MOVETYPE_NONE;
 +      self.model = "";
 +      self.solid = SOLID_TRIGGER;
 +      self.move_origin = self.origin;
 +      self.move_time = time;
 +}
 +
 +void ent_conveyor()
 +{
 +      float sf = ReadByte();
 +
 +      if(sf & 1)
 +      {
 +              self.warpzone_isboxy = 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.speed = ReadByte();
 +              self.state = ReadByte();
 +
 +              self.targetname = strzone(ReadString());
 +              self.target = strzone(ReadString());
 +
 +              conveyor_init();
 +      }
 +
 +      if(sf & 2)
 +              self.state = ReadByte();
 +}
 +#endif
index 8ce8e1f,0000000..79277c7
mode 100644,000000..100644
--- /dev/null
@@@ -1,960 -1,0 +1,960 @@@
-               return TRUE;
 +/*
 +
 +Doors are similar to buttons, but can spawn a fat trigger field around them
 +to open without a touch, and they link together to form simultanious
 +double/quad doors.
 +
 +Door.owner is the master door.  If there is only one door, it points to itself.
 +If multiple doors, all will point to a single one.
 +
 +Door.enemy chains from the master door through all doors linked in the chain.
 +
 +*/
 +
 +
 +/*
 +=============================================================================
 +
 +THINK FUNCTIONS
 +
 +=============================================================================
 +*/
 +
 +void() door_go_down;
 +void() door_go_up;
 +void() door_rotating_go_down;
 +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
 +
 +               //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 ();
 +                      } else
 +                      {
 +                              door_rotating_go_up ();
 +                      }
 +                              else
 +                      if (self.classname == "door")
 +                      {
 +                              door_go_down ();
 +                      } 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_hit_top()
 +{
 +      if (self.noise1 != "")
 +              sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
 +      self.state = STATE_TOP;
 +      if (self.spawnflags & DOOR_TOGGLE)
 +              return;         // don't come down automatically
 +      if (self.classname == "door")
 +      {
 +              self.think = door_go_down;
 +      } else
 +      {
 +              self.think = door_rotating_go_down;
 +      }
 +      self.nextthink = self.ltime + self.wait;
 +}
 +
 +void door_hit_bottom()
 +{
 +      if (self.noise1 != "")
 +              sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
 +      self.state = STATE_BOTTOM;
 +}
 +
 +void door_go_down()
 +{
 +      if (self.noise2 != "")
 +              sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
 +      if (self.max_health)
 +      {
 +              self.takedamage = DAMAGE_YES;
 +              self.health = self.max_health;
 +      }
 +      print(
 +#ifdef SVQC
 +      "Server ",
 +#elif defined(CSQC)
 +      "Client ",
 +#endif
 +      "going down at time ", ftos(time), "\n");
 +
 +      self.state = STATE_DOWN;
 +      SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, door_hit_bottom);
 +}
 +
 +void door_go_up()
 +{
 +      if (self.state == STATE_UP)
 +              return;         // already going up
 +
 +      if (self.state == STATE_TOP)
 +      {       // reset top wait time
 +              self.nextthink = self.ltime + self.wait;
 +              return;
 +      }
 +
 +      if (self.noise2 != "")
 +              sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
 +      self.state = STATE_UP;
 +      SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, door_hit_top);
 +
 +      string oldmessage;
 +      oldmessage = self.message;
 +      self.message = "";
 +      SUB_UseTargets();
 +      self.message = oldmessage;
 +}
 +
 +
 +/*
 +=============================================================================
 +
 +ACTIVATION FUNCTIONS
 +
 +=============================================================================
 +*/
 +
 +float door_check_keys(void)
 +{
 +      local entity door;
 +
 +
 +      if (self.owner)
 +              door = self.owner;
 +      else
 +              door = self;
 +
 +      // no key needed
 +      if (!door.itemkeys)
-               return FALSE;
++              return true;
 +
 +      // this door require a key
 +      // only a player can have a key
 +      if (!IS_PLAYER(other))
-               return TRUE;
++              return false;
 +
 +#ifdef SVQC
 +      if (item_keys_usekey(door, other))
 +      {
 +              // some keys were used
 +              if (other.key_door_messagetime <= time)
 +              {
 +
 +                      play2(other, "misc/talk.wav");
 +                      Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(door.itemkeys));
 +                      other.key_door_messagetime = time + 2;
 +              }
 +      }
 +      else
 +      {
 +              // no keys were used
 +              if (other.key_door_messagetime <= time)
 +              {
 +                      play2(other, "misc/talk.wav");
 +                      Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(door.itemkeys));
 +
 +                      other.key_door_messagetime = time + 2;
 +              }
 +      }
 +#endif
 +
 +      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 FALSE;
++              return true;
 +      }
 +      else
-       return TRUE;
++              return false;
 +}
 +
 +void door_fire()
 +{
 +      entity  oself;
 +      entity  starte;
 +
 +      if (self.owner != self)
 +              objerror ("door_fire: self.owner != self");
 +
 +      oself = self;
 +
 +      if (self.spawnflags & DOOR_TOGGLE)
 +      {
 +              if (self.state == STATE_UP || self.state == STATE_TOP)
 +              {
 +                      starte = self;
 +                      do
 +                      {
 +                              if (self.classname == "door")
 +                              {
 +                                      door_go_down ();
 +                              }
 +                              else
 +                              {
 +                                      door_rotating_go_down ();
 +                              }
 +                              self = self.enemy;
 +                      } while ( (self != starte) && (self != world) );
 +                      self = oself;
 +                      return;
 +              }
 +      }
 +
 +// trigger all paired doors
 +      starte = self;
 +      do
 +      {
 +              if (self.classname == "door")
 +              {
 +                      door_go_up ();
 +              } else
 +              {
 +                      // if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
 +                      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;
 +                      }
 +                      // 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)))))
 +                      {
 +                              door_rotating_go_up ();
 +                      }
 +              }
 +              self = self.enemy;
 +      } while ( (self != starte) && (self != world) );
 +      self = oself;
 +}
 +
 +void door_use()
 +{
 +      entity oself;
 +
 +      //dprint("door_use (model: ");dprint(self.model);dprint(")\n");
 +
 +      if (self.owner)
 +      {
 +              oself = self;
 +              self = self.owner;
 +              door_fire ();
 +              self = oself;
 +      }
 +}
 +
 +void door_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 +{
 +      entity oself;
 +      if(self.spawnflags & DOOR_NOSPLASH)
 +              if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
 +                      return;
 +      self.health = self.health - damage;
 +
 +      if (self.itemkeys)
 +      {
 +              // don't allow opening doors through damage if keys are required
 +              return;
 +      }
 +
 +      if (self.health <= 0)
 +      {
 +              oself = self;
 +              self = self.owner;
 +              self.health = self.max_health;
 +              self.takedamage = DAMAGE_NO;    // wil be reset upon return
 +              door_use ();
 +              self = oself;
 +      }
 +}
 +
 +
 +/*
 +================
 +door_touch
 +
 +Prints messages
 +================
 +*/
 +
 +void door_touch()
 +{
 +      if (!IS_PLAYER(other))
 +              return;
 +      if (self.owner.attack_finished_single > time)
 +              return;
 +
 +      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!!
 +#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()
 +{
 +      if (self.noise1 != "")
 +              sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
 +      self.state = STATE_TOP;
 +      if (self.spawnflags & DOOR_TOGGLE)
 +              return;         // don't come down automatically
 +      self.think = door_rotating_go_down;
 +      self.nextthink = self.ltime + self.wait;
 +}
 +
 +void door_rotating_hit_bottom()
 +{
 +      if (self.noise1 != "")
 +              sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
 +      if (self.lip==666) // self.lip is used to remember reverse opening direction for door_rotating
 +      {
 +              self.pos2 = '0 0 0' - self.pos2;
 +              self.lip = 0;
 +      }
 +      self.state = STATE_BOTTOM;
 +}
 +
 +void door_rotating_go_down()
 +{
 +      if (self.noise2 != "")
 +              sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
 +      if (self.max_health)
 +      {
 +              self.takedamage = DAMAGE_YES;
 +              self.health = self.max_health;
 +      }
 +
 +      self.state = STATE_DOWN;
 +      SUB_CalcAngleMove (self.pos1, TSPEED_LINEAR, self.speed, door_rotating_hit_bottom);
 +}
 +
 +void door_rotating_go_up()
 +{
 +      if (self.state == STATE_UP)
 +              return;         // already going up
 +
 +      if (self.state == STATE_TOP)
 +      {       // reset top wait time
 +              self.nextthink = self.ltime + self.wait;
 +              return;
 +      }
 +      if (self.noise2 != "")
 +              sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
 +      self.state = STATE_UP;
 +      SUB_CalcAngleMove (self.pos2, TSPEED_LINEAR, self.speed, door_rotating_hit_top);
 +
 +      string oldmessage;
 +      oldmessage = self.message;
 +      self.message = "";
 +      SUB_UseTargets();
 +      self.message = oldmessage;
 +}
 +
 +
 +/*
 +=========================================
 +door trigger
 +
 +Spawned if a door lacks a real activator
 +=========================================
 +*/
 +
 +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);
 +
-       Net_LinkEntity(trig, FALSE, 0, door_trigger_send);
++      return true;
 +}
 +
 +void door_trigger_link(entity trig)
 +{
-       ) { return FALSE; }
-       return TRUE;
++      Net_LinkEntity(trig, false, 0, door_trigger_send);
 +}
 +
 +void spawn_field(vector fmins, vector fmaxs)
 +{
 +      entity  trigger;
 +      vector  t1 = fmins, t2 = fmaxs;
 +
 +      trigger = spawn();
 +      trigger.classname = "doortriggerfield";
 +      trigger.movetype = MOVETYPE_NONE;
 +      trigger.solid = SOLID_TRIGGER;
 +      trigger.owner = self;
 +      trigger.touch = door_trigger_touch;
 +
 +      setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
 +      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))
 +      {
 +      }
 +      return cur;
 +}
 +
 +float LinkDoors_isconnected(entity e1, entity e2, entity pass)
 +{
 +      float DELTA = 4;
 +      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 TRUE;
++      ) { return false; }
++      return true;
 +}
 +
 +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)
 +      {
 +              self.owner = self.enemy = self;
 +
 +              if (self.health)
 +                      return;
 +              IFTARGETED
 +                      return;
 +              if (self.items)
 +                      return;
 +              spawn_field(self.absmin, self.absmax);
 +
 +              return;         // don't want to link this door
 +      }
 +
 +      FindConnectedComponent(self, enemy, LinkDoors_nextent, LinkDoors_isconnected, world);
 +
 +      // set owner, and make a loop of the chain
 +      dprint("LinkDoors: linking doors:");
 +      for(t = self; ; t = t.enemy)
 +      {
 +              dprint(" ", etos(t));
 +              t.owner = self;
 +              if(t.enemy == world)
 +              {
 +                      t.enemy = self;
 +                      break;
 +              }
 +      }
 +      dprint("\n");
 +
 +      // collect health, targetname, message, size
 +      cmins = self.absmin;
 +      cmaxs = self.absmax;
 +      for(t = self; ; t = t.enemy)
 +      {
 +              if(t.health && !self.health)
 +                      self.health = t.health;
 +              if((t.targetname != "") && (self.targetname == ""))
 +                      self.targetname = t.targetname;
 +              if((t.message != "") && (self.message == ""))
 +                      self.message = t.message;
 +              if (t.absmin_x < cmins_x)
 +                      cmins_x = t.absmin_x;
 +              if (t.absmin_y < cmins_y)
 +                      cmins_y = t.absmin_y;
 +              if (t.absmin_z < cmins_z)
 +                      cmins_z = t.absmin_z;
 +              if (t.absmax_x > cmaxs_x)
 +                      cmaxs_x = t.absmax_x;
 +              if (t.absmax_y > cmaxs_y)
 +                      cmaxs_y = t.absmax_y;
 +              if (t.absmax_z > cmaxs_z)
 +                      cmaxs_z = t.absmax_z;
 +              if(t.enemy == self)
 +                      break;
 +      }
 +
 +      // distribute health, targetname, message
 +      for(t = self; t; t = t.enemy)
 +      {
 +              t.health = self.health;
 +              t.targetname = self.targetname;
 +              t.message = self.message;
 +              if(t.enemy == self)
 +                      break;
 +      }
 +
 +      // shootable, or triggered doors just needed the owner/enemy links,
 +      // they don't spawn a field
 +
 +      if (self.health)
 +              return;
 +      IFTARGETED
 +              return;
 +      if (self.items)
 +              return;
 +
 +      spawn_field(cmins, cmaxs);
 +}
 +
 +
 +/*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
 +if two doors touch, they are assumed to be connected and operate as a unit.
 +
 +TOGGLE causes the door to wait in both the start and end states for a trigger event.
 +
 +START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
 +
 +GOLD_KEY causes the door to open only if the activator holds a gold key.
 +
 +SILVER_KEY causes the door to open only if the activator holds a silver key.
 +
 +"message"     is printed when the door is touched if it is a trigger door and it hasn't been fired yet
 +"angle"               determines the opening direction
 +"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
 +"health"      if set, door must be shot open
 +"speed"               movement speed (100 default)
 +"wait"                wait before returning (3 default, -1 = never return)
 +"lip"         lip remaining at end of move (8 default)
 +"dmg"         damage to inflict when blocked (2 default)
 +"sounds"
 +0)    no sound
 +1)    stone
 +2)    base
 +3)    stone chain
 +4)    screechy metal
 +FIXME: only one sound set available at the time being
 +
 +*/
 +
 +float door_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_DOOR);
 +      WriteByte(MSG_ENTITY, sf);
 +
 +      if(sf & SF_TRIGGER_INIT)
 +      {
 +              WriteString(MSG_ENTITY, self.classname);
 +              WriteByte(MSG_ENTITY, self.spawnflags);
 +              WriteShort(MSG_ENTITY, ((self.owner == self || !self.owner) ? -1 : num_for_edict(self.owner)));
 +              WriteShort(MSG_ENTITY, ((self.enemy == self || !self.enemy) ? -1 : num_for_edict(self.enemy)));
 +              WriteShort(MSG_ENTITY, num_for_edict(self));
 +
 +              WriteByte(MSG_ENTITY, self.scale);
 +
 +              WriteCoord(MSG_ENTITY, self.origin_x);
 +              WriteCoord(MSG_ENTITY, self.origin_y);
 +              WriteCoord(MSG_ENTITY, self.origin_z);
 +
 +              WriteString(MSG_ENTITY, self.model);
 +
 +              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);
 +
 +              WriteAngle(MSG_ENTITY, self.angles_x);
 +              WriteAngle(MSG_ENTITY, self.angles_y);
 +              WriteAngle(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);
 +
 +              WriteShort(MSG_ENTITY, self.wait);
 +              WriteShort(MSG_ENTITY, self.speed);
 +              WriteByte(MSG_ENTITY, self.lip);
 +              WriteByte(MSG_ENTITY, self.state);
 +              WriteShort(MSG_ENTITY, self.ltime);
 +      }
 +
 +      if(sf & SF_TRIGGER_RESET)
 +      {
 +              // client makes use of this, we do not
 +      }
 +
 +      if(sf & SF_TRIGGER_UPDATE)
 +      {
 +              WriteCoord(MSG_ENTITY, self.origin_x);
 +              WriteCoord(MSG_ENTITY, self.origin_y);
 +              WriteCoord(MSG_ENTITY, self.origin_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);
 +      }
 +
-       Net_LinkEntity(self, FALSE, 0, door_send);
++      return true;
 +}
 +
 +void door_link()
 +{
 +      // set size now, as everything is loaded
 +      FixSize(self);
++      Net_LinkEntity(self, false, 0, door_send);
 +}
 +
 +void door_init_startopen()
 +{
 +      setorigin (self, self.pos2);
 +      self.pos2 = self.pos1;
 +      self.pos1 = self.origin;
 +
 +      self.SendFlags |= SF_TRIGGER_UPDATE;
 +}
 +
 +#endif
 +
 +void door_reset()
 +{
 +      setorigin(self, self.pos1);
 +      self.velocity = '0 0 0';
 +      self.state = STATE_BOTTOM;
 +      self.think = func_null;
 +      self.nextthink = 0;
 +
 +#ifdef SVQC
 +      self.SendFlags |= SF_TRIGGER_RESET;
 +#endif
 +}
 +
 +#ifdef SVQC
 +
 +// spawnflags require key (for now only func_door)
 +void spawnfunc_func_door()
 +{
 +      // Quake 1 keys compatibility
 +      if (self.spawnflags & SPAWNFLAGS_GOLD_KEY)
 +              self.itemkeys |= ITEM_KEY_BIT(0);
 +      if (self.spawnflags & SPAWNFLAGS_SILVER_KEY)
 +              self.itemkeys |= ITEM_KEY_BIT(1);
 +
 +      SetMovedir ();
 +
 +      self.max_health = self.health;
 +      if (!InitMovingBrushTrigger())
 +              return;
 +      self.effects |= EF_LOWPRECISION;
 +      self.classname = "door";
 +
 +      self.blocked = door_blocked;
 +      self.use = door_use;
 +
 +      if(self.dmg && (self.message == ""))
 +              self.message = "was squished";
 +      if(self.dmg && (self.message2 == ""))
 +              self.message2 = "was squished by";
 +
 +      if (self.sounds > 0)
 +      {
 +              precache_sound ("plats/medplat1.wav");
 +              precache_sound ("plats/medplat2.wav");
 +              self.noise2 = "plats/medplat1.wav";
 +              self.noise1 = "plats/medplat2.wav";
 +      }
 +
 +      if (!self.speed)
 +              self.speed = 100;
 +      if (!self.wait)
 +              self.wait = 3;
 +      if (!self.lip)
 +              self.lip = 8;
 +
 +      self.pos1 = self.origin;
 +      self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
 +
 +// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
 +// but spawn in the open position
 +      if (self.spawnflags & DOOR_START_OPEN)
 +              InitializeEntity(self, door_init_startopen, INITPRIO_SETLOCATION);
 +
 +      self.state = STATE_BOTTOM;
 +
 +      if (self.health)
 +      {
 +              self.takedamage = DAMAGE_YES;
 +              self.event_damage = door_damage;
 +      }
 +
 +      if (self.items)
 +              self.wait = -1;
 +
 +      self.touch = door_touch;
 +
 +// LinkDoors can't be done until all of the doors have been spawned, so
 +// the sizes can be detected properly.
 +      InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
 +
 +      self.reset = door_reset;
 +}
 +
 +#elif defined(CSQC)
 +
 +void ent_door()
 +{
 +      float sf = ReadByte();
 +
 +      if(sf & SF_TRIGGER_INIT)
 +      {
 +              self.classname = strzone(ReadString());
 +              self.spawnflags = ReadByte();
 +              float myowner = ReadShort();
 +              float myenemy = ReadShort();
 +              self.sv_entnum = ReadShort();
 +
 +              self.scale = ReadByte();
 +
 +              self.origin_x = ReadCoord();
 +              self.origin_y = ReadCoord();
 +              self.origin_z = ReadCoord();
 +              setorigin(self, self.origin);
 +
 +              self.mdl = strzone(ReadString());
 +              setmodel(self, self.mdl);
 +
 +              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 = ReadAngle();
 +              self.angles_y = ReadAngle();
 +              self.angles_z = ReadAngle();
 +
 +              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 = ReadShort();
 +              self.speed = ReadShort();
 +              self.lip = ReadByte();
 +              self.state = ReadByte();
 +              self.ltime = ReadShort();
 +
 +              self.movetype = MOVETYPE_PUSH;
 +              self.solid = SOLID_BSP;
 +              self.trigger_touch = door_touch;
 +              self.draw = trigger_draw_generic;
 +              self.drawmask = MASK_NORMAL;
 +              self.move_time = time;
 +              self.use = door_use;
 +              self.blocked = door_blocked;
 +
 +              print(ftos(self.entnum), " ", ftos(self.sv_entnum), "\n");
 +
 +              self.owner = ((myowner == -1) ? self : findfloat(world, sv_entnum, myowner));
 +              self.enemy = ((myenemy == -1) ? self : findfloat(world, sv_entnum, myenemy));
 +      }
 +
 +      if(sf & SF_TRIGGER_RESET)
 +      {
 +              door_reset();
 +      }
 +
 +      if(sf & SF_TRIGGER_UPDATE)
 +      {
 +              self.origin_x = ReadCoord();
 +              self.origin_y = ReadCoord();
 +              self.origin_z = ReadCoord();
 +              setorigin(self, self.origin);
 +
 +              self.pos1_x = ReadCoord();
 +              self.pos1_y = ReadCoord();
 +              self.pos1_z = ReadCoord();
 +              self.pos2_x = ReadCoord();
 +              self.pos2_y = ReadCoord();
 +              self.pos2_z = ReadCoord();
 +      }
 +}
 +
 +#endif
index 09ded99,0000000..307fb77
mode 100644,000000..100644
--- /dev/null
@@@ -1,236 -1,0 +1,236 @@@
-       self.bot_attack = TRUE;
 +#ifdef SVQC
 +void() fd_secret_move1;
 +void() fd_secret_move2;
 +void() fd_secret_move3;
 +void() fd_secret_move4;
 +void() fd_secret_move5;
 +void() fd_secret_move6;
 +void() fd_secret_done;
 +
 +const float SECRET_OPEN_ONCE = 1;             // stays open
 +const float SECRET_1ST_LEFT = 2;              // 1st move is left of arrow
 +const float SECRET_1ST_DOWN = 4;              // 1st move is down from arrow
 +const float SECRET_NO_SHOOT = 8;              // only opened by trigger
 +const float SECRET_YES_SHOOT = 16;    // shootable even if targeted
 +
 +void fd_secret_use()
 +{
 +      float temp;
 +      string message_save;
 +
 +      self.health = 10000;
++      self.bot_attack = true;
 +
 +      // exit if still moving around...
 +      if (self.origin != self.oldorigin)
 +              return;
 +
 +      message_save = self.message;
 +      self.message = ""; // no more message
 +      SUB_UseTargets();                               // fire all targets / killtargets
 +      self.message = message_save;
 +
 +      self.velocity = '0 0 0';
 +
 +      // Make a sound, wait a little...
 +
 +      if (self.noise1 != "")
 +              sound(self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
 +      self.nextthink = self.ltime + 0.1;
 +
 +      temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
 +      makevectors(self.mangle);
 +
 +      if (!self.t_width)
 +      {
 +              if (self.spawnflags & SECRET_1ST_DOWN)
 +                      self.t_width = fabs(v_up * self.size);
 +              else
 +                      self.t_width = fabs(v_right * self.size);
 +      }
 +
 +      if (!self.t_length)
 +              self.t_length = fabs(v_forward * self.size);
 +
 +      if (self.spawnflags & SECRET_1ST_DOWN)
 +              self.dest1 = self.origin - v_up * self.t_width;
 +      else
 +              self.dest1 = self.origin + v_right * (self.t_width * temp);
 +
 +      self.dest2 = self.dest1 + v_forward * self.t_length;
 +      SUB_CalcMove(self.dest1, TSPEED_LINEAR, self.speed, fd_secret_move1);
 +      if (self.noise2 != "")
 +              sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
 +}
 +
 +void fd_secret_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 +{
 +      fd_secret_use();
 +}
 +
 +// Wait after first movement...
 +void fd_secret_move1()
 +{
 +      self.nextthink = self.ltime + 1.0;
 +      self.think = fd_secret_move2;
 +      if (self.noise3 != "")
 +              sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
 +}
 +
 +// Start moving sideways w/sound...
 +void fd_secret_move2()
 +{
 +      if (self.noise2 != "")
 +              sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
 +      SUB_CalcMove(self.dest2, TSPEED_LINEAR, self.speed, fd_secret_move3);
 +}
 +
 +// Wait here until time to go back...
 +void fd_secret_move3()
 +{
 +      if (self.noise3 != "")
 +              sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
 +      if (!(self.spawnflags & SECRET_OPEN_ONCE))
 +      {
 +              self.nextthink = self.ltime + self.wait;
 +              self.think = fd_secret_move4;
 +      }
 +}
 +
 +// Move backward...
 +void fd_secret_move4()
 +{
 +      if (self.noise2 != "")
 +              sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
 +      SUB_CalcMove(self.dest1, TSPEED_LINEAR, self.speed, fd_secret_move5);
 +}
 +
 +// Wait 1 second...
 +void fd_secret_move5()
 +{
 +      self.nextthink = self.ltime + 1.0;
 +      self.think = fd_secret_move6;
 +      if (self.noise3 != "")
 +              sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
 +}
 +
 +void fd_secret_move6()
 +{
 +      if (self.noise2 != "")
 +              sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
 +      SUB_CalcMove(self.oldorigin, TSPEED_LINEAR, self.speed, fd_secret_done);
 +}
 +
 +void fd_secret_done()
 +{
 +      if (self.spawnflags&SECRET_YES_SHOOT)
 +      {
 +              self.health = 10000;
 +              self.takedamage = DAMAGE_YES;
 +              //self.th_pain = fd_secret_use;
 +      }
 +      if (self.noise3 != "")
 +              sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
 +}
 +
 +void secret_blocked()
 +{
 +      if (time < self.attack_finished_single)
 +              return;
 +      self.attack_finished_single = time + 0.5;
 +      //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
 +}
 +
 +/*
 +==============
 +secret_touch
 +
 +Prints messages
 +================
 +*/
 +void secret_touch()
 +{
 +      if (!other.iscreature)
 +              return;
 +      if (self.attack_finished_single > time)
 +              return;
 +
 +      self.attack_finished_single = time + 2;
 +
 +      if (self.message)
 +      {
 +              if (IS_CLIENT(other))
 +                      centerprint(other, self.message);
 +              play2(other, "misc/talk.wav");
 +      }
 +}
 +
 +void secret_reset()
 +{
 +      if (self.spawnflags&SECRET_YES_SHOOT)
 +      {
 +              self.health = 10000;
 +              self.takedamage = DAMAGE_YES;
 +      }
 +      setorigin(self, self.oldorigin);
 +      self.think = func_null;
 +      self.nextthink = 0;
 +}
 +
 +/*QUAKED spawnfunc_func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
 +Basic secret door. Slides back, then to the side. Angle determines direction.
 +wait  = # of seconds before coming back
 +1st_left = 1st move is left of arrow
 +1st_down = 1st move is down from arrow
 +always_shoot = even if targeted, keep shootable
 +t_width = override WIDTH to move back (or height if going down)
 +t_length = override LENGTH to move sideways
 +"dmg"         damage to inflict when blocked (2 default)
 +
 +If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
 +"sounds"
 +1) medieval
 +2) metal
 +3) base
 +*/
 +
 +void spawnfunc_func_door_secret()
 +{
 +      /*if (!self.deathtype) // map makers can override this
 +              self.deathtype = " got in the way";*/
 +
 +      if (!self.dmg)
 +              self.dmg = 2;
 +
 +      // Magic formula...
 +      self.mangle = self.angles;
 +      self.angles = '0 0 0';
 +      self.classname = "door";
 +      if (!InitMovingBrushTrigger())
 +              return;
 +      self.effects |= EF_LOWPRECISION;
 +
 +      self.touch = secret_touch;
 +      self.blocked = secret_blocked;
 +      self.speed = 50;
 +      self.use = fd_secret_use;
 +      IFTARGETED
 +      {
 +      }
 +      else
 +              self.spawnflags |= SECRET_YES_SHOOT;
 +
 +      if(self.spawnflags&SECRET_YES_SHOOT)
 +      {
 +              self.health = 10000;
 +              self.takedamage = DAMAGE_YES;
 +              self.event_damage = fd_secret_damage;
 +      }
 +      self.oldorigin = self.origin;
 +      if (!self.wait)
 +              self.wait = 5;          // 5 seconds before closing
 +
 +      self.reset = secret_reset;
 +      secret_reset();
 +}
 +#endif
index dc03693,0000000..290c2e9
mode 100644,000000..100644
--- /dev/null
@@@ -1,17 -1,0 +1,19 @@@
++#include "include.qh"
++
 +#include "bobbing.qc"
 +#include "breakable.qc"
 +#include "button.qc"
 +#include "conveyor.qc"
 +#include "door.qc"
 +#include "door_rotating.qc"
 +#include "door_secret.qc"
 +#include "fourier.qc"
 +#include "ladder.qc"
 +#include "pendulum.qc"
 +#include "plat.qc"
 +#include "pointparticles.qc"
 +#include "rainsnow.qc"
 +#include "rotating.qc"
 +#include "stardust.qc"
 +#include "train.qc"
 +#include "vectormamamam.qc"
index 70740c2,0000000..cca6f91
mode 100644,000000..100644
--- /dev/null
@@@ -1,4 -1,0 +1,9 @@@
++#ifndef TRIGGERS_FUNC_INCLUDE_H
++#define TRIGGERS_FUNC_INCLUDE_H
++
 +#include "conveyor.qh"
 +#include "door.qh"
 +#include "ladder.qh"
 +#include "plat.qh"
++
++#endif
index 76cda75,0000000..483fef8
mode 100644,000000..100644
--- /dev/null
@@@ -1,107 -1,0 +1,107 @@@
-       return TRUE;
 +void func_ladder_touch()
 +{
 +#ifdef SVQC
 +      if (!other.iscreature)
 +              return;
 +      if (other.vehicle_flags & VHF_ISVEHICLE)
 +              return;
 +#endif
 +#ifdef CSQC
 +      if(other.classname != "csqcmodel")
 +              return;
 +#endif
 +
 +      EXACTTRIGGER_TOUCH;
 +
 +      other.ladder_time = time + 0.1;
 +      other.ladder_entity = self;
 +}
 +
 +#ifdef SVQC
 +float func_ladder_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_LADDER);
 +
 +      WriteString(MSG_ENTITY, self.classname);
 +      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);
 +
-       Net_LinkEntity(self, FALSE, 0, func_ladder_send);
++      return true;
 +}
 +
 +void func_ladder_link()
 +{
++      Net_LinkEntity(self, false, 0, func_ladder_send);
 +}
 +
 +void spawnfunc_func_ladder()
 +{
 +      EXACTTRIGGER_INIT;
 +      self.touch = func_ladder_touch;
 +
 +      func_ladder_link();
 +}
 +
 +void spawnfunc_func_water()
 +{
 +      EXACTTRIGGER_INIT;
 +      self.touch = func_ladder_touch;
 +
 +      func_ladder_link();
 +}
 +
 +#elif defined(CSQC)
 +.float speed;
 +
 +void ent_func_ladder()
 +{
 +      self.classname = strzone(ReadString());
 +      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.solid = SOLID_TRIGGER;
 +      self.draw = trigger_draw_generic;
 +      self.trigger_touch = func_ladder_touch;
 +      self.drawmask = MASK_NORMAL;
 +      self.move_time = time;
 +}
 +#endif
index 7184c5b,0000000..5ac8b2a
mode 100644,000000..100644
--- /dev/null
@@@ -1,226 -1,0 +1,226 @@@
-       return TRUE;
 +#ifdef SVQC
 +void plat_delayedinit()
 +{
 +      plat_spawn_inside_trigger ();   // the "start moving" trigger
 +}
 +
 +float plat_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_PLAT);
 +      WriteByte(MSG_ENTITY, sf);
 +
 +      if(sf & SF_TRIGGER_INIT)
 +      {
 +              WriteShort(MSG_ENTITY, num_for_edict(self));
 +              WriteString(MSG_ENTITY, self.target);
 +              WriteString(MSG_ENTITY, self.target2);
 +              WriteString(MSG_ENTITY, self.target3);
 +              WriteString(MSG_ENTITY, self.target4);
 +              WriteString(MSG_ENTITY, self.targetname);
 +
 +              WriteByte(MSG_ENTITY, self.platmovetype_start);
 +              WriteByte(MSG_ENTITY, self.platmovetype_turn);
 +              WriteByte(MSG_ENTITY, self.platmovetype_end);
 +
 +              WriteCoord(MSG_ENTITY, self.origin_x);
 +              WriteCoord(MSG_ENTITY, self.origin_y);
 +              WriteCoord(MSG_ENTITY, self.origin_z);
 +
 +              WriteString(MSG_ENTITY, self.model);
 +
 +              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.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);
 +
 +              WriteAngle(MSG_ENTITY, self.angles_x);
 +              WriteAngle(MSG_ENTITY, self.angles_y);
 +              WriteAngle(MSG_ENTITY, self.angles_z);
 +
 +              WriteAngle(MSG_ENTITY, self.mangle_x);
 +              WriteAngle(MSG_ENTITY, self.mangle_y);
 +              WriteAngle(MSG_ENTITY, self.mangle_z);
 +
 +              WriteShort(MSG_ENTITY, self.speed);
 +              WriteShort(MSG_ENTITY, self.height);
 +              WriteByte(MSG_ENTITY, self.lip);
 +              WriteByte(MSG_ENTITY, self.state);
 +
 +              WriteShort(MSG_ENTITY, self.dmg);
 +      }
 +
 +      if(sf & SF_TRIGGER_RESET)
 +      {
 +              // used on client
 +      }
 +
-       Net_LinkEntity(self, 0, FALSE, plat_send);
++      return true;
 +}
 +
 +void plat_link()
 +{
++      Net_LinkEntity(self, 0, false, plat_send);
 +}
 +
 +void spawnfunc_func_plat()
 +{
 +      if (self.sounds == 0)
 +              self.sounds = 2;
 +
 +    if(self.spawnflags & 4)
 +        self.dmg = 10000;
 +
 +    if(self.dmg && (self.message == ""))
 +              self.message = "was squished";
 +    if(self.dmg && (self.message2 == ""))
 +              self.message2 = "was squished by";
 +
 +      if (self.sounds == 1)
 +      {
 +              precache_sound ("plats/plat1.wav");
 +              precache_sound ("plats/plat2.wav");
 +              self.noise = "plats/plat1.wav";
 +              self.noise1 = "plats/plat2.wav";
 +      }
 +
 +      if (self.sounds == 2)
 +      {
 +              precache_sound ("plats/medplat1.wav");
 +              precache_sound ("plats/medplat2.wav");
 +              self.noise = "plats/medplat1.wav";
 +              self.noise1 = "plats/medplat2.wav";
 +      }
 +
 +      if (self.sound1)
 +      {
 +              precache_sound (self.sound1);
 +              self.noise = self.sound1;
 +      }
 +      if (self.sound2)
 +      {
 +              precache_sound (self.sound2);
 +              self.noise1 = self.sound2;
 +      }
 +
 +      self.mangle = self.angles;
 +      self.angles = '0 0 0';
 +
 +      self.classname = "plat";
 +      if (!InitMovingBrushTrigger())
 +              return;
 +      self.effects |= EF_LOWPRECISION;
 +      setsize (self, self.mins , self.maxs);
 +
 +      self.blocked = plat_crush;
 +
 +      if (!self.speed)
 +              self.speed = 150;
 +      if (!self.lip)
 +              self.lip = 16;
 +      if (!self.height)
 +              self.height = self.size_z - self.lip;
 +
 +      self.pos1 = self.origin;
 +      self.pos2 = self.origin;
 +      self.pos2_z = self.origin_z - self.height;
 +
 +      self.reset = plat_reset;
 +      plat_reset();
 +
 +      plat_link();
 +
 +      InitializeEntity(self, plat_delayedinit, INITPRIO_FINDTARGET);
 +}
 +#elif defined(CSQC)
 +void plat_draw()
 +{
 +
 +}
 +
 +void ent_plat()
 +{
 +      float sf = ReadByte();
 +
 +      if(sf & SF_TRIGGER_INIT)
 +      {
 +              self.sv_entnum = ReadShort();
 +              self.target = strzone(ReadString());
 +              self.target2 = strzone(ReadString());
 +              self.target3 = strzone(ReadString());
 +              self.target4 = strzone(ReadString());
 +              self.targetname = strzone(ReadString());
 +
 +              self.platmovetype_start = ReadByte();
 +              self.platmovetype_turn = ReadByte();
 +              self.platmovetype_end = ReadByte();
 +
 +              self.origin_x = ReadCoord();
 +              self.origin_y = ReadCoord();
 +              self.origin_z = ReadCoord();
 +              setorigin(self, self.origin);
 +
 +              self.model = strzone(ReadString());
 +              setmodel(self, self.model);
 +
 +              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.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.angles_x = ReadAngle();
 +              self.angles_y = ReadAngle();
 +              self.angles_z = ReadAngle();
 +
 +              self.mangle_x = ReadAngle();
 +              self.mangle_y = ReadAngle();
 +              self.mangle_z = ReadAngle();
 +
 +              self.speed = ReadShort();
 +              self.height = ReadShort();
 +              self.lip = ReadByte();
 +              self.state = ReadByte();
 +
 +              self.dmg = ReadShort();
 +
 +              self.solid = SOLID_BSP;
 +              self.movetype = MOVETYPE_PUSH;
 +              self.drawmask = MASK_NORMAL;
 +              self.draw = plat_draw;
 +              self.use = plat_use;
 +
 +              plat_reset(); // also called here
 +      }
 +
 +      if(sf & SF_TRIGGER_RESET)
 +      {
 +              plat_reset();
 +      }
 +}
 +#endif
index 61922f4,0000000..e86b156
mode 100644,000000..100644
--- /dev/null
@@@ -1,92 -1,0 +1,92 @@@
-       Net_LinkEntity(self, FALSE, 0, rainsnow_SendEntity);
 +#ifdef SVQC
 +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);
++      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);
 +}
 +#endif
index e442eb5,0000000..14da459
mode 100644,000000..100644
--- /dev/null
@@@ -1,165 -1,0 +1,165 @@@
-               self.train_wait_turning = TRUE;
 +#ifdef SVQC
 +.float train_wait_turning;
 +void() train_next;
 +void train_wait()
 +{
 +      entity oldself;
 +      oldself = self;
 +      self = self.enemy;
 +      SUB_UseTargets();
 +      self = oldself;
 +      self.enemy = world;
 +
 +      // if turning is enabled, the train will turn toward the next point while waiting
 +      if(self.platmovetype_turn && !self.train_wait_turning)
 +      {
 +              entity targ, cp;
 +              vector ang;
 +              targ = find(world, targetname, self.target);
 +              if((self.spawnflags & 1) && targ.curvetarget)
 +                      cp = find(world, targetname, targ.curvetarget);
 +              else
 +                      cp = world;
 +
 +              if(cp) // bezier curves movement
 +                      ang = cp.origin - (self.origin - self.view_ofs); // use the origin of the control point of the next path_corner
 +              else // linear movement
 +                      ang = targ.origin - (self.origin - self.view_ofs); // use the origin of the next path_corner
 +              ang = vectoangles(ang);
 +              ang_x = -ang_x; // flip up / down orientation
 +
 +              if(self.wait > 0) // slow turning
 +                      SUB_CalcAngleMove(ang, TSPEED_TIME, self.ltime - time + self.wait, train_wait);
 +              else // instant turning
 +                      SUB_CalcAngleMove(ang, TSPEED_TIME, 0.0000001, train_wait);
-               self.train_wait_turning = FALSE;
++              self.train_wait_turning = true;
 +              return;
 +      }
 +
 +      if(self.noise != "")
 +              stopsoundto(MSG_BROADCAST, self, CH_TRIGGER_SINGLE); // send this as unreliable only, as the train will resume operation shortly anyway
 +
 +      if(self.wait < 0 || self.train_wait_turning) // no waiting or we already waited while turning
 +      {
-               self.platmovetype_turn = TRUE;
++              self.train_wait_turning = false;
 +              train_next();
 +      }
 +      else
 +      {
 +              self.think = train_next;
 +              self.nextthink = self.ltime + self.wait;
 +      }
 +}
 +
 +void train_next()
 +{
 +      entity targ, cp = world;
 +      vector cp_org = '0 0 0';
 +
 +      targ = find(world, targetname, self.target);
 +      self.target = targ.target;
 +      if (self.spawnflags & 1)
 +      {
 +              if(targ.curvetarget)
 +              {
 +                      cp = find(world, targetname, targ.curvetarget); // get its second target (the control point)
 +                      cp_org = cp.origin - self.view_ofs; // no control point found, assume a straight line to the destination
 +              }
 +      }
 +      if (self.target == "")
 +              objerror("train_next: no next target");
 +      self.wait = targ.wait;
 +      if (!self.wait)
 +              self.wait = 0.1;
 +
 +      if(targ.platmovetype)
 +      {
 +              // this path_corner contains a movetype overrider, apply it
 +              self.platmovetype_start = targ.platmovetype_start;
 +              self.platmovetype_end = targ.platmovetype_end;
 +      }
 +      else
 +      {
 +              // this path_corner doesn't contain a movetype overrider, use the train's defaults
 +              self.platmovetype_start = self.platmovetype_start_default;
 +              self.platmovetype_end = self.platmovetype_end_default;
 +      }
 +
 +      if (targ.speed)
 +      {
 +              if (cp)
 +                      SUB_CalcMove_Bezier(cp_org, targ.origin - self.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
 +              else
 +                      SUB_CalcMove(targ.origin - self.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
 +      }
 +      else
 +      {
 +              if (cp)
 +                      SUB_CalcMove_Bezier(cp_org, targ.origin - self.view_ofs, TSPEED_LINEAR, self.speed, train_wait);
 +              else
 +                      SUB_CalcMove(targ.origin - self.view_ofs, TSPEED_LINEAR, self.speed, train_wait);
 +      }
 +
 +      if(self.noise != "")
 +              sound(self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
 +}
 +
 +void func_train_find()
 +{
 +      entity targ;
 +      targ = find(world, targetname, self.target);
 +      self.target = targ.target;
 +      if (self.target == "")
 +              objerror("func_train_find: no next target");
 +      setorigin(self, targ.origin - self.view_ofs);
 +      self.nextthink = self.ltime + 1;
 +      self.think = train_next;
 +}
 +
 +/*QUAKED spawnfunc_func_train (0 .5 .8) ?
 +Ridable platform, targets spawnfunc_path_corner path to follow.
 +speed : speed the train moves (can be overridden by each spawnfunc_path_corner)
 +target : targetname of first spawnfunc_path_corner (starts here)
 +*/
 +void spawnfunc_func_train()
 +{
 +      if (self.noise != "")
 +              precache_sound(self.noise);
 +
 +      if (self.target == "")
 +              objerror("func_train without a target");
 +      if (!self.speed)
 +              self.speed = 100;
 +
 +      if (!InitMovingBrushTrigger())
 +              return;
 +      self.effects |= EF_LOWPRECISION;
 +      
 +      if (self.spawnflags & 2)
 +      {
++              self.platmovetype_turn = true;
 +              self.view_ofs = '0 0 0'; // don't offset a rotating train, origin works differently now
 +      }
 +      else
 +              self.view_ofs = self.mins;
 +
 +      // wait for targets to spawn
 +      InitializeEntity(self, func_train_find, INITPRIO_SETLOCATION);
 +
 +      self.blocked = generic_plat_blocked;
 +      if(self.dmg && (self.message == ""))
 +              self.message = " was squished";
 +    if(self.dmg && (self.message2 == ""))
 +              self.message2 = "was squished by";
 +      if(self.dmg && (!self.dmgtime))
 +              self.dmgtime = 0.25;
 +      self.dmgtime2 = time;
 +
 +      if(!set_platmovetype(self, self.platmovetype))
 +              return;
 +      self.platmovetype_start_default = self.platmovetype_start;
 +      self.platmovetype_end_default = self.platmovetype_end;
 +
 +      // TODO make a reset function for this one
 +}
 +#endif
index b90a75c,0000000..8189d3b
mode 100644,000000..100644
--- /dev/null
@@@ -1,17 -1,0 +1,19 @@@
++#include "include.qh"
++
 +// some required common stuff
 +#include "subs.qc"
 +#include "triggers.qc"
 +#include "platforms.qc"
 +
 +// func
 +#include "func/include.qc"
 +
 +// misc
 +#include "misc/include.qc"
 +
 +// target
 +#include "target/include.qc"
 +
 +// trigger
 +#include "trigger/include.qc"
 +
index 705dec7,0000000..1cd37db
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,24 @@@
++#ifndef TRIGGERS_INCLUDE_H
++#define TRIGGERS_INCLUDE_H
++
 +// some required common stuff
 +#ifdef CSQC
 +      #include "../../server/item_key.qh"
 +#endif
 +#include "triggers.qh"
 +#include "subs.qh"
 +#include "platforms.qh"
 +
 +// func
 +#include "func/include.qh"
 +
 +// misc
 +#include "misc/include.qh"
 +
 +// target
 +#include "target/include.qh"
 +
 +// trigger
 +#include "trigger/include.qh"
++
++#endif
index 16212a4,0000000..8c5678f
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,5 @@@
++#include "include.qh"
++
 +#include "corner.qc"
 +#include "follow.qc"
 +#include "laser.qc"
index 8f9537e,0000000..6f43e2a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1 -1,0 +1,6 @@@
++#ifndef TRIGGERS_MISC_INCLUDE_H
++#define TRIGGERS_MISC_INCLUDE_H
++
 +// nothing yet
++
++#endif
index 987777a,0000000..2aaf399
mode 100644,000000..100644
--- /dev/null
@@@ -1,257 -1,0 +1,257 @@@
-       Net_LinkEntity(self, FALSE, 0, laser_SendEntity);
 +#ifdef SVQC
 +.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;
 +}
 +#endif
index 03c2f0f,0000000..fd4825e
mode 100644,000000..100644
--- /dev/null
@@@ -1,273 -1,0 +1,273 @@@
-       return TRUE;
 +void generic_plat_blocked()
 +{
 +#ifdef SVQC
 +      if(self.dmg && other.takedamage != DAMAGE_NO)
 +      {
 +              if(self.dmgtime2 < time)
 +              {
 +                      Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
 +                      self.dmgtime2 = time + self.dmgtime;
 +              }
 +
 +              // Gib dead/dying stuff
 +              if(other.deadflag != DEAD_NO)
 +                      Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
 +      }
 +#endif
 +}
 +
 +#ifdef SVQC
 +float plat_trigger_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_PLAT_TRIGGER);
 +      WriteShort(MSG_ENTITY, num_for_edict(self.enemy));
 +
 +      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);
-                               Net_LinkEntity(trigger, FALSE, 0, plat_trigger_send);
++      return true;
 +}
 +
 +void plat_spawn_inside_trigger()
 +{
 +      entity trigger;
 +      vector tmin, tmax;
 +
 +      trigger = spawn();
 +      trigger.touch = plat_center_touch;
 +      trigger.movetype = MOVETYPE_NONE;
 +      trigger.solid = SOLID_TRIGGER;
 +      trigger.enemy = self;
 +
 +      tmin = self.absmin + '25 25 0';
 +      tmax = self.absmax - '25 25 -8';
 +      tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8);
 +      if (self.spawnflags & PLAT_LOW_TRIGGER)
 +              tmax_z = tmin_z + 8;
 +
 +      if (self.size_x <= 50)
 +      {
 +              tmin_x = (self.mins_x + self.maxs_x) / 2;
 +              tmax_x = tmin_x + 1;
 +      }
 +      if (self.size_y <= 50)
 +      {
 +              tmin_y = (self.mins_y + self.maxs_y) / 2;
 +              tmax_y = tmin_y + 1;
 +      }
 +
 +      if(tmin_x < tmax_x)
 +              if(tmin_y < tmax_y)
 +                      if(tmin_z < tmax_z)
 +                      {
 +                              setsize (trigger, tmin, tmax);
-                       return TRUE; // no checking, return immediately
++                              Net_LinkEntity(trigger, false, 0, plat_trigger_send);
 +                              return;
 +                      }
 +
 +      // otherwise, something is fishy...
 +      remove(trigger);
 +      objerror("plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
 +}
 +#elif defined(CSQC)
 +void ent_plat_trigger()
 +{
 +      float myenemy = 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.enemy = findfloat(world, sv_entnum, myenemy);
 +      if(!self.enemy) { print("^1BAD BAD BAD!!!\n"); }
 +      self.drawmask = MASK_NORMAL;
 +      self.draw = trigger_draw_generic;
 +      self.trigger_touch = plat_center_touch;
 +      self.solid = SOLID_TRIGGER;
 +}
 +#endif
 +
 +void plat_hit_top()
 +{
 +      sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
 +      self.state = 1;
 +      self.think = plat_go_down;
 +      self.nextthink = self.ltime + 3;
 +}
 +
 +void plat_hit_bottom()
 +{
 +      sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
 +      self.state = 2;
 +}
 +
 +void plat_go_down()
 +{
 +      sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
 +      self.state = 3;
 +      SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, plat_hit_bottom);
 +}
 +
 +void plat_go_up()
 +{
 +      sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
 +      self.state = 4;
 +      SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, plat_hit_top);
 +}
 +
 +void plat_center_touch()
 +{
 +#ifdef SVQC
 +      if (!other.iscreature)
 +              return;
 +
 +      if (other.health <= 0)
 +              return;
 +#elif defined(CSQC)
 +      if (!IS_PLAYER(other))
 +              return;
 +#endif
 +
 +#ifdef CSQC
 +      print("Got this far\n");
 +#endif
 +
 +      self = self.enemy;
 +      if (self.state == 2)
 +              plat_go_up ();
 +      else if (self.state == 1)
 +              self.nextthink = self.ltime + 1;        // delay going down
 +}
 +
 +void plat_outside_touch()
 +{
 +#ifdef SVQC
 +      if (!other.iscreature)
 +              return;
 +
 +      if (other.health <= 0)
 +              return;
 +#elif defined(CSQC)
 +      if (!IS_PLAYER(other))
 +              return;
 +#endif
 +
 +      self = self.enemy;
 +      if (self.state == 1)
 +              plat_go_down ();
 +}
 +
 +void plat_trigger_use()
 +{
 +      if (self.think)
 +              return;         // already activated
 +      plat_go_down();
 +}
 +
 +
 +void plat_crush()
 +{
 +      if((self.spawnflags & 4) && (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_NO))
 +              {   // Shall we bite?
 +                      Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
 +                      // Gib dead/dying stuff
 +                      if(other.deadflag != DEAD_NO)
 +                              Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
 +              }
 +#endif
 +
 +              if (self.state == 4)
 +                      plat_go_down ();
 +              else if (self.state == 3)
 +                      plat_go_up ();
 +      // when in other states, then the plat_crush event came delayed after
 +      // plat state already had changed
 +      // this isn't a bug per se!
 +      }
 +}
 +
 +void plat_use()
 +{
 +      self.use = func_null;
 +      if (self.state != 4)
 +              objerror ("plat_use: not in up state");
 +      plat_go_down();
 +}
 +
 +.string sound1, sound2;
 +
 +void plat_reset()
 +{
 +      IFTARGETED
 +      {
 +              setorigin (self, self.pos1);
 +              self.state = 4;
 +              self.use = plat_use;
 +      }
 +      else
 +      {
 +              setorigin (self, self.pos2);
 +              self.state = 2;
 +              self.use = plat_trigger_use;
 +      }
 +
 +#ifdef SVQC
 +      self.SendFlags |= SF_TRIGGER_RESET;
 +#endif
 +}
 +
 +#ifdef SVQC
 +.float platmovetype_start_default, platmovetype_end_default;
 +float set_platmovetype(entity e, string s)
 +{
 +      // sets platmovetype_start and platmovetype_end based on a string consisting of two values
 +
 +      float n;
 +      n = tokenize_console(s);
 +      if(n > 0)
 +              e.platmovetype_start = stof(argv(0));
 +      else
 +              e.platmovetype_start = 0;
 +
 +      if(n > 1)
 +              e.platmovetype_end = stof(argv(1));
 +      else
 +              e.platmovetype_end = e.platmovetype_start;
 +
 +      if(n > 2)
 +              if(argv(2) == "force")
-               return FALSE;
++                      return true; // no checking, return immediately
 +
 +      if(!cubic_speedfunc_is_sane(e.platmovetype_start, e.platmovetype_end))
 +      {
 +              objerror("Invalid platform move type; platform would go in reverse, which is not allowed.");
-       return TRUE;
++              return false;
 +      }
 +
++      return true;
 +}
 +#endif
index 84d9f7a,0000000..69ad2fa
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,20 @@@
++#ifndef PLATFORMS_H
++#define PLATFORMS_H
++
 +.float dmgtime2;
 +
 +void() plat_center_touch;
 +void() plat_outside_touch;
 +void() plat_trigger_use;
 +void() plat_go_up;
 +void() plat_go_down;
 +void() plat_crush;
 +const float PLAT_LOW_TRIGGER = 1;
 +
 +.float dmg;
 +
 +#ifdef CSQC
 +void ent_plat_trigger();
 +#endif
++
++#endif
index 2c2ba7d,0000000..bf09948
mode 100644,000000..100644
--- /dev/null
@@@ -1,67 -1,0 +1,72 @@@
++#ifndef SUBS_H
++#define SUBS_H
++
 +void SUB_Remove();
 +void SUB_SetFade (entity ent, float when, float fading_time);
 +void SUB_VanishOrRemove (entity ent);
 +
 +.vector               finaldest, finalangle;          //plat.qc stuff
 +.void()               think1;
 +.float state;
 +.float                t_length, t_width;
 +
 +.vector destvec;
 +.vector destvec2;
 +
 +// player animation state
 +.float animstate_startframe;
 +.float animstate_numframes;
 +.float animstate_framerate;
 +.float animstate_starttime;
 +.float animstate_endtime;
 +.float animstate_override;
 +.float animstate_looping;
 +
 +.float        delay;
 +.float        wait;
 +.float        lip;
 +.float        speed;
 +.float        sounds;
 +.string  platmovetype;
 +.float platmovetype_start, platmovetype_end;
 +
 +entity activator;
 +
 +.string killtarget;
 +
 +.vector       pos1, pos2;
 +.vector       mangle;
 +
 +.string target2;
 +.string target3;
 +.string target4;
 +.string curvetarget;
 +.float target_random;
 +.float trigger_reverse;
 +
 +// 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;
 +
 +.vector dest1, dest2;
 +
 +#ifdef CSQC
 +// this stuff is defined in the server side engine VM, so we must define it separately here
 +.float takedamage;
 +const float DAMAGE_NO = 0;
 +const float DAMAGE_YES        = 1;
 +const float DAMAGE_AIM        = 2;
 +
 +float STATE_TOP               = 0;
 +float STATE_BOTTOM    = 1;
 +float STATE_UP                = 2;
 +float STATE_DOWN              = 3;
 +
 +.string               noise, noise1, noise2, noise3;  // contains names of wavs to play
 +
 +.float                max_health;             // players maximum health is stored here
 +#endif
++
++#endif
index a8c876b,0000000..3b8e024
mode 100644,000000..100644
--- /dev/null
@@@ -1,5 -1,0 +1,7 @@@
++#include "include.qh"
++
 +#include "changelevel.qc"
 +#include "music.qc"
 +#include "spawn.qc"
 +#include "speaker.qc"
 +#include "voicescript.qc"
index 8f9537e,0000000..cadbf37
mode 100644,000000..100644
--- /dev/null
@@@ -1,1 -1,0 +1,6 @@@
++#ifndef TRIGGERS_TARGET_INCLUDE_H
++#define TRIGGERS_TARGET_INCLUDE_H
++
 +// nothing yet
++
++#endif
index 5aa095d,0000000..fb38dad
mode 100644,000000..100644
--- /dev/null
@@@ -1,136 -1,0 +1,146 @@@
- .float lifetime;
++#if defined(CSQC)
++#elif defined(MENUQC)
++#elif defined(SVQC)
++      #include "../../../dpdefs/progsdefs.qh"
++    #include "../../../dpdefs/dpextensions.qh"
++    #include "../../constants.qh"
++    #include "../../../server/constants.qh"
++    #include "../../../server/defs.qh"
++#endif
++
 +#ifdef SVQC
-               WriteCoord(MSG_ENTITY, self.origin_x);
-               WriteCoord(MSG_ENTITY, self.origin_y);
-               WriteCoord(MSG_ENTITY, self.origin_z);
++
 +// values:
 +//   volume
 +//   noise
 +//   targetname
 +//   lifetime
 +//   fade_time
 +//   fade_rate
 +// when triggered, the music is overridden for activator until lifetime (or forever, if lifetime is 0)
 +// when targetname is not set, THIS ONE is default
 +void target_music_sendto(float to, float is)
 +{
 +      WriteByte(to, SVC_TEMPENTITY);
 +      WriteByte(to, TE_CSQC_TARGET_MUSIC);
 +      WriteShort(to, num_for_edict(self));
 +      WriteByte(to, self.volume * 255.0 * is);
 +      WriteByte(to, self.fade_time * 16.0);
 +      WriteByte(to, self.fade_rate * 16.0);
 +      WriteByte(to, self.lifetime);
 +      WriteString(to, self.noise);
 +}
 +void target_music_reset()
 +{
 +      if(self.targetname == "")
 +              target_music_sendto(MSG_ALL, 1);
 +}
 +void target_music_use()
 +{
 +      if(!activator)
 +              return;
 +      if(IS_REAL_CLIENT(activator))
 +      {
 +              msg_entity = activator;
 +              target_music_sendto(MSG_ONE, 1);
 +      }
 +      entity head;
 +      FOR_EACH_SPEC(head) if(head.enemy == activator) { msg_entity = head; target_music_sendto(MSG_ONE, 1); }
 +}
 +void spawnfunc_target_music()
 +{
 +      self.use = target_music_use;
 +      self.reset = target_music_reset;
 +      if(!self.volume)
 +              self.volume = 1;
 +      if(self.targetname == "")
 +              target_music_sendto(MSG_INIT, 1);
 +      else
 +              target_music_sendto(MSG_INIT, 0);
 +}
 +void TargetMusic_RestoreGame()
 +{
 +      for(self = world; (self = find(self, classname, "target_music")); )
 +      {
 +              if(self.targetname == "")
 +                      target_music_sendto(MSG_INIT, 1);
 +              else
 +                      target_music_sendto(MSG_INIT, 0);
 +      }
 +}
 +// values:
 +//   volume
 +//   noise
 +//   targetname
 +//   fade_time
 +// spawnflags:
 +//   1 = START_OFF
 +// when triggered, it is disabled/enabled for everyone
 +float trigger_music_SendEntity(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
 +      sf &= ~0x80;
 +      if(self.cnt)
 +              sf |= 0x80;
 +      WriteByte(MSG_ENTITY, sf);
 +      if(sf & 4)
 +      {
-                       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.origin.x);
++              WriteCoord(MSG_ENTITY, self.origin.y);
++              WriteCoord(MSG_ENTITY, self.origin.z);
 +      }
 +      if(sf & 1)
 +      {
 +              if(self.model != "null")
 +              {
 +                      WriteShort(MSG_ENTITY, self.modelindex);
-                       WriteCoord(MSG_ENTITY, self.maxs_x);
-                       WriteCoord(MSG_ENTITY, self.maxs_y);
-                       WriteCoord(MSG_ENTITY, self.maxs_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);
 +              }
 +              else
 +              {
 +                      WriteShort(MSG_ENTITY, 0);
-       Net_LinkEntity(self, FALSE, 0, trigger_music_SendEntity);
++                      WriteCoord(MSG_ENTITY, self.maxs.x);
++                      WriteCoord(MSG_ENTITY, self.maxs.y);
++                      WriteCoord(MSG_ENTITY, self.maxs.z);
 +              }
 +              WriteByte(MSG_ENTITY, self.volume * 255.0);
 +              WriteByte(MSG_ENTITY, self.fade_time * 16.0);
 +              WriteByte(MSG_ENTITY, self.fade_rate * 16.0);
 +              WriteString(MSG_ENTITY, self.noise);
 +      }
 +      return 1;
 +}
 +void trigger_music_reset()
 +{
 +      self.cnt = !(self.spawnflags & 1);
 +      self.SendFlags |= 0x80;
 +}
 +void trigger_music_use()
 +{
 +      self.cnt = !self.cnt;
 +      self.SendFlags |= 0x80;
 +}
 +void spawnfunc_trigger_music()
 +{
 +      if(self.model != "")
 +              setmodel(self, self.model);
 +      if(!self.volume)
 +              self.volume = 1;
 +      if(!self.modelindex)
 +      {
 +              setorigin(self, self.origin + self.mins);
 +              setsize(self, '0 0 0', self.maxs - self.mins);
 +      }
 +      trigger_music_reset();
 +
 +      self.use = trigger_music_use;
 +      self.reset = trigger_music_reset;
 +
++      Net_LinkEntity(self, false, 0, trigger_music_SendEntity);
 +}
 +#endif
index 0000000,0000000..400e4b8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++#ifndef TARGET_MUSIC_H
++#define TARGET_MUSIC_H
++
++.float lifetime;
++
++#endif
index d661b98,0000000..98a3209
mode 100644,000000..100644
--- /dev/null
@@@ -1,337 -1,0 +1,347 @@@
-                       data_x = -1;
-                       data_y = FIELD_STRING;
++#if defined(CSQC)
++#elif defined(MENUQC)
++#elif defined(SVQC)
++      #include "../../../dpdefs/progsdefs.qh"
++    #include "../../../dpdefs/dpextensions.qh"
++    #include "../../util.qh"
++    #include "../../../server/defs.qh"
++#endif
++
 +#ifdef SVQC
++
 +// spawner entity
 +// "classname" "target_spawn"
 +// "message" "fieldname value fieldname value ..."
 +// "spawnflags"
 +//   1 = call the spawn function
 +//   2 = trigger on map load
 +
 +float target_spawn_initialized;
 +.void() target_spawn_spawnfunc;
 +float target_spawn_spawnfunc_field;
 +.entity target_spawn_activator;
 +.float target_spawn_id;
 +float target_spawn_count;
 +
 +void target_spawn_helper_setmodel()
 +{
 +      setmodel(self, self.model);
 +}
 +
 +void target_spawn_helper_setsize()
 +{
 +      setsize(self, self.mins, self.maxs);
 +}
 +
 +void target_spawn_edit_entity(entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act)
 +{
 +      float i, n, valuefieldpos;
 +      string key, value, valuefield, valueoffset, valueoffsetrandom;
 +      entity valueent;
 +      vector data, data2;
 +      entity oldself;
 +      entity oldactivator;
 +
 +      n = tokenize_console(msg);
 +
 +      for(i = 0; i < n-1; i += 2)
 +      {
 +              key = argv(i);
 +              value = argv(i+1);
 +              if(key == "$")
 +              {
-                       if(data_y == 0) // undefined field, i.e., invalid type
++                      data.x = -1;
++                      data.y = FIELD_STRING;
 +              }
 +              else
 +              {
 +                      data = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", key)));
-                                       switch(data_y)
++                      if(data.y == 0) // undefined field, i.e., invalid type
 +                      {
 +                              print("target_spawn: invalid/unknown entity key ", key, " specified, ignored!\n");
 +                              continue;
 +                      }
 +              }
 +              if(substring(value, 0, 1) == "$")
 +              {
 +                      value = substring(value, 1, strlen(value) - 1);
 +                      if(substring(value, 0, 1) == "$")
 +                      {
 +                              // deferred replacement
 +                              // do nothing
 +                              // useful for creating target_spawns with this!
 +                      }
 +                      else
 +                      {
 +                              // replace me!
 +                              valuefieldpos = strstrofs(value, "+", 0);
 +                              valueoffset = "";
 +                              if(valuefieldpos != -1)
 +                              {
 +                                      valueoffset = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
 +                                      value = substring(value, 0, valuefieldpos);
 +                              }
 +
 +                              valuefieldpos = strstrofs(valueoffset, "+", 0);
 +                              valueoffsetrandom = "";
 +                              if(valuefieldpos != -1)
 +                              {
 +                                      valueoffsetrandom = substring(valueoffset, valuefieldpos + 1, strlen(valueoffset) - valuefieldpos - 1);
 +                                      valueoffset = substring(valueoffset, 0, valuefieldpos);
 +                              }
 +
 +                              valuefieldpos = strstrofs(value, ".", 0);
 +                              valuefield = "";
 +                              if(valuefieldpos != -1)
 +                              {
 +                                      valuefield = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
 +                                      value = substring(value, 0, valuefieldpos);
 +                              }
 +
 +                              if(value == "self")
 +                              {
 +                                      valueent = self;
 +                                      value = "";
 +                              }
 +                              else if(value == "activator")
 +                              {
 +                                      valueent = act;
 +                                      value = "";
 +                              }
 +                              else if(value == "other")
 +                              {
 +                                      valueent = other;
 +                                      value = "";
 +                              }
 +                              else if(value == "pusher")
 +                              {
 +                                      if(time < act.pushltime)
 +                                              valueent = act.pusher;
 +                                      else
 +                                              valueent = world;
 +                                      value = "";
 +                              }
 +                              else if(value == "target")
 +                              {
 +                                      valueent = e;
 +                                      value = "";
 +                              }
 +                              else if(value == "killtarget")
 +                              {
 +                                      valueent = kt;
 +                                      value = "";
 +                              }
 +                              else if(value == "target2")
 +                              {
 +                                      valueent = t2;
 +                                      value = "";
 +                              }
 +                              else if(value == "target3")
 +                              {
 +                                      valueent = t3;
 +                                      value = "";
 +                              }
 +                              else if(value == "target4")
 +                              {
 +                                      valueent = t4;
 +                                      value = "";
 +                              }
 +                              else if(value == "time")
 +                              {
 +                                      valueent = world;
 +                                      value = ftos(time);
 +                              }
 +                              else
 +                              {
 +                                      print("target_spawn: invalid/unknown variable replacement ", value, " specified, ignored!\n");
 +                                      continue;
 +                              }
 +
 +                              if(valuefield == "")
 +                              {
 +                                      if(value == "")
 +                                              value = ftos(num_for_edict(valueent));
 +                              }
 +                              else
 +                              {
 +                                      if(value != "")
 +                                      {
 +                                              print("target_spawn: try to get a field of a non-entity, ignored!\n");
 +                                              continue;
 +                                      }
 +                                      data2 = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", valuefield)));
 +                                      if(data2_y == 0) // undefined field, i.e., invalid type
 +                                      {
 +                                              print("target_spawn: invalid/unknown entity key replacement ", valuefield, " specified, ignored!\n");
 +                                              continue;
 +                                      }
 +                                      value = getentityfieldstring(data2_x, valueent);
 +                              }
 +
 +                              if(valueoffset != "")
 +                              {
-                                       switch(data_y)
++                                      switch(data.y)
 +                                      {
 +                                              case FIELD_STRING:
 +                                                      value = strcat(value, valueoffset);
 +                                                      break;
 +                                              case FIELD_FLOAT:
 +                                                      value = ftos(stof(value) + stof(valueoffset));
 +                                                      break;
 +                                              case FIELD_VECTOR:
 +                                                      value = vtos(stov(value) + stov(valueoffset));
 +                                                      break;
 +                                              default:
 +                                                      print("target_spawn: only string, float and vector fields can do calculations, calculation ignored!\n");
 +                                                      break;
 +                                      }
 +                              }
 +
 +                              if(valueoffsetrandom != "")
 +                              {
-                       if(data_y == FIELD_VECTOR)
++                                      switch(data.y)
 +                                      {
 +                                              case FIELD_FLOAT:
 +                                                      value = ftos(stof(value) + random() * stof(valueoffsetrandom));
 +                                                      break;
 +                                              case FIELD_VECTOR:
 +                                                      data2 = stov(valueoffsetrandom);
 +                                                      value = vtos(stov(value) + random() * data2_x * '1 0 0' + random() * data2_y * '0 1 0' + random() * data2_z * '0 0 1');
 +                                                      break;
 +                                              default:
 +                                                      print("target_spawn: only float and vector fields can do random calculations, calculation ignored!\n");
 +                                                      break;
 +                                      }
 +                              }
 +                      }
 +              }
 +              if(key == "$")
 +              {
 +                      if(substring(value, 0, 1) == "_")
 +                              value = strcat("target_spawn_helper", value);
 +                      putentityfieldstring(target_spawn_spawnfunc_field, e, value);
 +
 +                      oldself = self;
 +                      oldactivator = activator;
 +
 +                      self = e;
 +                      activator = act;
 +
 +                      self.target_spawn_spawnfunc();
 +
 +                      self = oldself;
 +                      activator = oldactivator;
 +              }
 +              else
 +              {
-                       putentityfieldstring(data_x, e, value);
++                      if(data.y == FIELD_VECTOR)
 +                              value = strreplace("'", "", value); // why?!?
-                       if(prev_y == 0)
++                      putentityfieldstring(data.x, e, value);
 +              }
 +      }
 +}
 +
 +void target_spawn_useon(entity e)
 +{
 +      self.target_spawn_activator = activator;
 +      target_spawn_edit_entity(
 +              e,
 +              self.message,
 +              find(world, targetname, self.killtarget),
 +              find(world, targetname, self.target2),
 +              find(world, targetname, self.target3),
 +              find(world, targetname, self.target4),
 +              activator
 +      );
 +}
 +
 +float target_spawn_cancreate()
 +{
 +      float c;
 +      entity e;
 +
 +      c = self.count;
 +      if(c == 0) // no limit?
 +              return 1;
 +
 +      ++c; // increase count to not include MYSELF
 +      for(e = world; (e = findfloat(e, target_spawn_id, self.target_spawn_id)); --c)
 +              ;
 +
 +      // if c now is 0, we have AT LEAST the given count (maybe more), so don't spawn any more
 +      if(c == 0)
 +              return 0;
 +      return 1;
 +}
 +
 +void target_spawn_use()
 +{
 +      entity e;
 +
 +      if(self.target == "")
 +      {
 +              // spawn new entity
 +              if(!target_spawn_cancreate())
 +                      return;
 +              e = spawn();
 +              target_spawn_useon(e);
 +              e.target_spawn_id = self.target_spawn_id;
 +      }
 +      else if(self.target == "*activator")
 +      {
 +              // edit entity
 +              if(activator)
 +                      target_spawn_useon(activator);
 +      }
 +      else
 +      {
 +              // edit entity
 +              for(e = world; (e = find(e, targetname, self.target)); )
 +                      target_spawn_useon(e);
 +      }
 +}
 +
 +void target_spawn_spawnfirst()
 +{
 +      activator = self.target_spawn_activator;
 +      if(self.spawnflags & 2)
 +              target_spawn_use();
 +}
 +
 +void initialize_field_db()
 +{
 +      if(!target_spawn_initialized)
 +      {
 +              float n, i;
 +              string fn;
 +              vector prev, new;
 +              float ft;
 +
 +              n = numentityfields();
 +              for(i = 0; i < n; ++i)
 +              {
 +                      fn = entityfieldname(i);
 +                      ft = entityfieldtype(i);
 +                      new = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
 +                      prev = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", fn)));
++                      if(prev.y == 0)
 +                      {
 +                              db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(new));
 +                              if(fn == "target_spawn_spawnfunc")
 +                                      target_spawn_spawnfunc_field = i;
 +                      }
 +              }
 +
 +              target_spawn_initialized = 1;
 +      }
 +}
 +
 +void spawnfunc_target_spawn()
 +{
 +      initialize_field_db();
 +      self.use = target_spawn_use;
 +      self.message = strzone(strreplace("'", "\"", self.message));
 +      self.target_spawn_id = ++target_spawn_count;
 +      InitializeEntity(self, target_spawn_spawnfirst, INITPRIO_LAST);
 +}
 +#endif
index a656afc,0000000..a709a1f
mode 100644,000000..100644
--- /dev/null
@@@ -1,106 -1,0 +1,106 @@@
-       if(self.state != TRUE)
 +#ifdef SVQC
 +.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;
 +
-       self.state = TRUE;
++      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 = FALSE;
++      self.state = true;
 +      IFTARGETED
 +      {
 +              self.use = trigger_gravity_use;
 +              if(self.spawnflags & 2)
++                      self.state = false;
 +      }
 +}
 +#endif
index fbf11a5,0000000..3a15a77
mode 100644,000000..100644
--- /dev/null
@@@ -1,92 -1,0 +1,92 @@@
-                       return TRUE;
 +#ifdef SVQC
 +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 FALSE;
++                      return true;
 +
++      return false;
 +}
 +#endif
index dbdfaa0,0000000..d436881
mode 100644,000000..100644
--- /dev/null
@@@ -1,152 -1,0 +1,146 @@@
- // tZorks trigger impulse / gravity
- .float radius;
- .float falloff;
- .float strength;
- .float lastpushtime;
 +#ifdef SVQC
 +// 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;
 +        }
 +    }
 +}
 +#endif
index 0000000,0000000..67d6361
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10 @@@
++#ifndef TRIGGER_IMPULSE_H
++#define TRIGGER_IMPULSE_H
++
++// tZorks trigger impulse / gravity
++.float radius;
++.float falloff;
++.float strength;
++.float lastpushtime;
++
++#endif
index 5a0e83f,0000000..a71de89
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,22 @@@
++#include "include.qh"
++
 +#include "counter.qc"
 +#include "delay.qc"
 +#include "disablerelay.qc"
 +#include "flipflop.qc"
 +#include "gamestart.qc"
 +#include "gravity.qc"
 +#include "heal.qc"
 +#include "hurt.qc"
 +#include "impulse.qc"
 +#include "jumppads.qc"
 +#include "magicear.qc"
 +#include "monoflop.qc"
 +#include "multi.qc"
 +#include "multivibrator.qc"
 +#include "relay.qc"
 +#include "relay_activators.qc"
 +#include "relay_if.qc"
 +#include "relay_teamcheck.qc"
 +#include "secret.qc"
 +#include "swamp.qc"
index 5ec3175,0000000..6f4825b
mode 100644,000000..100644
--- /dev/null
@@@ -1,4 -1,0 +1,9 @@@
++#ifndef TRIGGERS_TRIGGER_INCLUDE_H
++#define TRIGGERS_TRIGGER_INCLUDE_H
++
 +#include "multi.qh"
 +#include "jumppads.qh"
 +#include "secret.qh"
 +#include "swamp.qh"
++
++#endif
index 67fd6a9,0000000..d60e4ff
mode 100644,000000..100644
--- /dev/null
@@@ -1,496 -1,0 +1,491 @@@
 +// TODO: split target_push and put it in the target folder
- float trigger_push_calculatevelocity_flighttime;
 +#ifdef SVQC
++#include "jumppads.qh"
 +
 +void trigger_push_use()
 +{
 +      if(teamplay)
 +      {
 +              self.team = activator.team;
 +              self.SendFlags |= 2;
 +      }
 +}
 +#endif
 +
-       zdist = torg_z - org_z;
 +/*
 +      trigger_push_calculatevelocity
 +
 +      Arguments:
 +        org - origin of the object which is to be pushed
 +        tgt - target entity (can be either a point or a model entity; if it is
 +              the latter, its midpoint is used)
 +        ht  - jump height, measured from the higher one of org and tgt's midpoint
 +
 +      Returns: velocity for the jump
 +      the global trigger_push_calculatevelocity_flighttime is set to the total
 +      jump time
 + */
 +
 +vector trigger_push_calculatevelocity(vector org, entity tgt, float ht)
 +{
 +      float grav, sdist, zdist, vs, vz, jumpheight;
 +      vector sdir, torg;
 +
 +      torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
 +
 +      grav = PHYS_GRAVITY;
 +      if(PHYS_ENTGRAVITY(other))
 +              grav *= PHYS_ENTGRAVITY(other);
 +
-       if(!solution_z)
-               solution_y = solution_x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0)
++      zdist = torg.z - org.z;
 +      sdist = vlen(torg - org - zdist * '0 0 1');
 +      sdir = normalize(torg - org - zdist * '0 0 1');
 +
 +      // how high do we need to push the player?
 +      jumpheight = fabs(ht);
 +      if(zdist > 0)
 +              jumpheight = jumpheight + zdist;
 +
 +      /*
 +              STOP.
 +
 +              You will not understand the following equations anyway...
 +              But here is what I did to get them.
 +
 +              I used the functions
 +
 +                s(t) = t * vs
 +                z(t) = t * vz - 1/2 grav t^2
 +
 +              and solved for:
 +
 +                s(ti) = sdist
 +                z(ti) = zdist
 +                max(z, ti) = jumpheight
 +
 +              From these three equations, you will find the three parameters vs, vz
 +              and ti.
 +       */
 +
 +      // push him so high...
 +      vz = sqrt(fabs(2 * grav * jumpheight)); // NOTE: sqrt(positive)!
 +
 +      // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump!
 +      if(ht < 0)
 +              if(zdist < 0)
 +                      vz = -vz;
 +
 +      vector solution;
 +      solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist"
 +      // ALWAYS solvable because jumpheight >= zdist
-               solution_x = solution_y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually)
++      if(!solution.z)
++              solution.y = solution.x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0)
 +      if(zdist == 0)
-                       trigger_push_calculatevelocity_flighttime = solution_y;
++              solution.x = solution.y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually)
 +
 +      if(zdist < 0)
 +      {
 +              // down-jump
 +              if(ht < 0)
 +              {
 +                      // almost straight line type
 +                      // jump apex is before the jump
 +                      // we must take the larger one
-                       trigger_push_calculatevelocity_flighttime = solution_y;
++                      trigger_push_calculatevelocity_flighttime = solution.y;
 +              }
 +              else
 +              {
 +                      // regular jump
 +                      // jump apex is during the jump
 +                      // we must take the larger one too
-                       trigger_push_calculatevelocity_flighttime = solution_x;
++                      trigger_push_calculatevelocity_flighttime = solution.y;
 +              }
 +      }
 +      else
 +      {
 +              // up-jump
 +              if(ht < 0)
 +              {
 +                      // almost straight line type
 +                      // jump apex is after the jump
 +                      // we must take the smaller one
-                       trigger_push_calculatevelocity_flighttime = solution_y;
++                      trigger_push_calculatevelocity_flighttime = solution.x;
 +              }
 +              else
 +              {
 +                      // regular jump
 +                      // jump apex is during the jump
 +                      // we must take the larger one
++                      trigger_push_calculatevelocity_flighttime = solution.y;
 +              }
 +      }
 +      vs = sdist / trigger_push_calculatevelocity_flighttime;
 +
 +      // finally calculate the velocity
 +      return sdir * vs + '0 0 1' * vz;
 +}
 +
 +void trigger_push_touch()
 +{
 +      if (self.active == ACTIVE_NOT)
 +              return;
 +
 +#ifdef SVQC
 +      if (!isPushable(other))
 +              return;
 +#endif
 +
 +      if(self.team)
 +              if(((self.spawnflags & 4) == 0) == (DIFF_TEAM(self, other)))
 +                      return;
 +
 +      EXACTTRIGGER_TOUCH;
 +
 +      if(self.enemy)
 +      {
 +              other.velocity = trigger_push_calculatevelocity(other.origin, self.enemy, self.height);
 +      }
 +      else if(self.target)
 +      {
 +              entity e;
 +              RandomSelection_Init();
 +              for(e = world; (e = find(e, targetname, self.target)); )
 +              {
 +                      if(e.cnt)
 +                              RandomSelection_Add(e, 0, string_null, e.cnt, 1);
 +                      else
 +                              RandomSelection_Add(e, 0, string_null, 1, 1);
 +              }
 +              other.velocity = trigger_push_calculatevelocity(other.origin, RandomSelection_chosen_ent, self.height);
 +      }
 +      else
 +      {
 +              other.velocity = self.movedir;
 +      }
 +
 +      UNSET_ONGROUND(other);
 +
 +#ifdef SVQC
 +      if (IS_PLAYER(other))
 +      {
 +              // reset tracking of oldvelocity for impact damage (sudden velocity changes)
 +              other.oldvelocity = other.velocity;
 +
 +              if(self.pushltime < time)  // prevent "snorring" sound when a player hits the jumppad more than once
 +              {
 +                      // flash when activated
 +                      pointparticles(particleeffectnum("jumppad_activate"), other.origin, other.velocity, 1);
 +                      sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
 +                      self.pushltime = time + 0.2;
 +              }
-                       float i;
-                       float found;
-                       found = FALSE;
-                       for(i = 0; i < other.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
 +              if(IS_REAL_CLIENT(other) || IS_BOT_CLIENT(other))
 +              {
-                                       found = TRUE;
++                      bool found = false;
++                      for(int i = 0; i < other.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
 +                              if(other.(jumppadsused[i]) == self)
-                               animdecide_setaction(other, ANIMACTION_JUMP, TRUE);
++                                      found = true;
 +                      if(!found)
 +                      {
 +                              other.(jumppadsused[other.jumppadcount % NUM_JUMPPADSUSED]) = self;
 +                              other.jumppadcount = other.jumppadcount + 1;
 +                      }
 +
 +                      if(IS_REAL_CLIENT(other))
 +                      {
 +                              if(self.message)
 +                                      centerprint(other, self.message);
 +                      }
 +                      else
 +                              other.lastteleporttime = time;
 +
 +                      if (other.deadflag == DEAD_NO)
-                       other.jumppadcount = TRUE;
++                              animdecide_setaction(other, ANIMACTION_JUMP, true);
 +              }
 +              else
-       org_z = self.absmax_z - PL_MIN_z;
++                      other.jumppadcount = true;
 +
 +              // reset tracking of who pushed you into a hazard (for kill credit)
 +              other.pushltime = 0;
 +              other.istypefrag = 0;
 +      }
 +
 +      if(self.enemy.target)
 +      {
 +              entity oldself;
 +              oldself = self;
 +              activator = other;
 +              self = self.enemy;
 +              SUB_UseTargets();
 +              self = oldself;
 +      }
 +
 +      if (other.flags & FL_PROJECTILE)
 +      {
 +              other.angles = vectoangles (other.velocity);
 +              switch(other.movetype)
 +              {
 +                      case MOVETYPE_FLY:
 +                              other.movetype = MOVETYPE_TOSS;
 +                              other.gravity = 1;
 +                              break;
 +                      case MOVETYPE_BOUNCEMISSILE:
 +                              other.movetype = MOVETYPE_BOUNCE;
 +                              other.gravity = 1;
 +                              break;
 +              }
 +              UpdateCSQCProjectile(other);
 +      }
 +
 +      if (self.spawnflags & PUSH_ONCE)
 +      {
 +              self.touch = func_null;
 +              self.think = SUB_Remove;
 +              self.nextthink = time;
 +      }
 +#endif
 +}
 +
 +#ifdef SVQC
 +void trigger_push_link();
 +void trigger_push_updatelink();
 +#endif
 +void trigger_push_findtarget()
 +{
 +      entity t;
 +      vector org;
 +
 +      // first calculate a typical start point for the jump
 +      org = (self.absmin + self.absmax) * 0.5;
-       return TRUE;
++      org.z = self.absmax.z - PL_MIN_z;
 +
 +      if (self.target)
 +      {
 +              float n = 0;
 +              for(t = world; (t = find(t, targetname, self.target)); )
 +              {
 +                      ++n;
 +#ifdef SVQC
 +                      entity e = spawn();
 +                      setorigin(e, org);
 +                      setsize(e, PL_MIN, PL_MAX);
 +                      e.velocity = trigger_push_calculatevelocity(org, t, self.height);
 +                      tracetoss(e, e);
 +                      if(e.movetype == MOVETYPE_NONE)
 +                              waypoint_spawnforteleporter(self, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
 +                      remove(e);
 +#endif
 +              }
 +
 +              if(!n)
 +              {
 +                      // no dest!
 +#ifdef SVQC
 +                      objerror ("Jumppad with nonexistant target");
 +#endif
 +                      return;
 +              }
 +              else if(n == 1)
 +              {
 +                      // exactly one dest - bots love that
 +                      self.enemy = find(world, targetname, self.target);
 +              }
 +              else
 +              {
 +                      // have to use random selection every single time
 +                      self.enemy = world;
 +              }
 +      }
 +#ifdef SVQC
 +      else
 +      {
 +              entity e = spawn();
 +              setorigin(e, org);
 +              setsize(e, PL_MIN, PL_MAX);
 +              e.velocity = self.movedir;
 +              tracetoss(e, e);
 +              waypoint_spawnforteleporter(self, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
 +              remove(e);
 +      }
 +
 +      trigger_push_link();
 +      defer(0.1, trigger_push_updatelink);
 +#endif
 +}
 +
 +#ifdef SVQC
 +float trigger_push_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH);
 +      WriteByte(MSG_ENTITY, sf);
 +
 +      if(sf & 1)
 +      {
 +              WriteString(MSG_ENTITY, self.target);
 +              WriteByte(MSG_ENTITY, self.team);
 +              WriteInt24_t(MSG_ENTITY, self.spawnflags);
 +              WriteByte(MSG_ENTITY, self.active);
 +              WriteByte(MSG_ENTITY, self.warpzone_isboxy);
 +              WriteByte(MSG_ENTITY, self.height);
 +              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);
 +      }
 +
 +      if(sf & 2)
 +      {
 +              WriteByte(MSG_ENTITY, self.team);
 +              WriteByte(MSG_ENTITY, self.active);
 +      }
 +
-       Net_LinkEntity(self, FALSE, 0, trigger_push_send);
++      return true;
 +}
 +
 +void trigger_push_updatelink()
 +{
 +      self.SendFlags |= 1;
 +}
 +
 +void trigger_push_link()
 +{
-       return TRUE;
++      Net_LinkEntity(self, false, 0, trigger_push_send);
 +}
 +#endif
 +#ifdef SVQC
 +/*
 + * ENTITY PARAMETERS:
 + *
 + *   target:  target of jump
 + *   height:  the absolute value is the height of the highest point of the jump
 + *            trajectory above the higher one of the player and the target.
 + *            the sign indicates whether the highest point is INSIDE (positive)
 + *            or OUTSIDE (negative) of the jump trajectory. General rule: use
 + *            positive values for targets mounted on the floor, and use negative
 + *            values to target a point on the ceiling.
 + *   movedir: if target is not set, this * speed * 10 is the velocity to be reached.
 + */
 +void spawnfunc_trigger_push()
 +{
 +      SetMovedir ();
 +
 +      EXACTTRIGGER_INIT;
 +
 +      self.active = ACTIVE_ACTIVE;
 +      self.use = trigger_push_use;
 +      self.touch = trigger_push_touch;
 +
 +      // normal push setup
 +      if (!self.speed)
 +              self.speed = 1000;
 +      self.movedir = self.movedir * self.speed * 10;
 +
 +      if (!self.noise)
 +              self.noise = "misc/jumppad.wav";
 +      precache_sound (self.noise);
 +
 +      // this must be called to spawn the teleport waypoints for bots
 +      InitializeEntity(self, trigger_push_findtarget, INITPRIO_FINDTARGET);
 +}
 +
 +
 +float target_push_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
 +
 +      WriteByte(MSG_ENTITY, self.cnt);
 +      WriteString(MSG_ENTITY, self.targetname);
 +      WriteCoord(MSG_ENTITY, self.origin_x);
 +      WriteCoord(MSG_ENTITY, self.origin_y);
 +      WriteCoord(MSG_ENTITY, self.origin_z);
 +
-       Net_LinkEntity(self, FALSE, 0, target_push_send);
++      return true;
 +}
 +
 +void target_push_link()
 +{
++      Net_LinkEntity(self, false, 0, target_push_send);
 +      self.SendFlags |= 1; // update
 +}
 +
 +void spawnfunc_target_push() { target_push_link(); }
 +void spawnfunc_info_notnull() { target_push_link(); }
 +void spawnfunc_target_position() { target_push_link(); }
 +
 +#endif
 +
 +#ifdef CSQC
 +void ent_trigger_push()
 +{
 +      float sf = ReadByte();
 +
 +      if(sf & 1)
 +      {
 +              self.classname = "jumppad";
 +              self.target = strzone(ReadString());
 +              float mytm = ReadByte(); if(mytm) { self.team = mytm - 1; }
 +              self.spawnflags = ReadInt24_t();
 +              self.active = ReadByte();
 +              self.warpzone_isboxy = ReadByte();
 +              self.height = 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.solid = SOLID_TRIGGER;
 +              self.draw = trigger_draw_generic;
 +              self.trigger_touch = trigger_push_touch;
 +              self.drawmask = MASK_ENGINE;
 +              self.move_time = time;
 +              trigger_push_findtarget();
 +      }
 +
 +      if(sf & 2)
 +      {
 +              self.team = ReadByte();
 +              self.active = ReadByte();
 +      }
 +}
 +
 +void ent_target_push()
 +{
 +      self.classname = "push_target";
 +      self.cnt = ReadByte();
 +      self.targetname = strzone(ReadString());
 +      self.origin_x = ReadCoord();
 +      self.origin_y = ReadCoord();
 +      self.origin_z = ReadCoord();
 +      setorigin(self, self.origin);
 +
 +      self.drawmask = MASK_ENGINE;
 +}
 +#endif
index 6330dc3,0000000..bb0f475
mode 100644,000000..100644
--- /dev/null
@@@ -1,12 -1,0 +1,68 @@@
- const float PUSH_ONCE = 1;
- const float PUSH_SILENT = 2;
++#ifndef T_JUMPPADS_H
++#define T_JUMPPADS_H
++
++const float PUSH_ONCE         = 1;
++const float PUSH_SILENT               = 2;
++
++.float pushltime;
++.float istypefrag;
++.float height;
++
++const int NUM_JUMPPADSUSED = 3;
++.float jumppadcount;
++.entity jumppadsused[NUM_JUMPPADSUSED];
++
++float trigger_push_calculatevelocity_flighttime;
++
++#ifdef SVQC
++void() SUB_UseTargets;
++void trigger_push_use();
++#endif
++
 +#ifdef CSQC
 +void ent_trigger_push();
++
 +void ent_target_push();
 +#endif
 +
- .float pushltime;
- .float istypefrag;
++/*
++      trigger_push_calculatevelocity
 +
- void() SUB_UseTargets;
++      Arguments:
++        org - origin of the object which is to be pushed
++        tgt - target entity (can be either a point or a model entity; if it is
++              the latter, its midpoint is used)
++        ht  - jump height, measured from the higher one of org and tgt's midpoint
 +
++      Returns: velocity for the jump
++      the global trigger_push_calculatevelocity_flighttime is set to the total
++      jump time
++ */
++
++vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
++
++void trigger_push_touch();
++
++.vector dest;
++void trigger_push_findtarget();
++
++/*
++ * ENTITY PARAMETERS:
++ *
++ *   target:  target of jump
++ *   height:  the absolute value is the height of the highest point of the jump
++ *            trajectory above the higher one of the player and the target.
++ *            the sign indicates whether the highest point is INSIDE (positive)
++ *            or OUTSIDE (negative) of the jump trajectory. General rule: use
++ *            positive values for targets mounted on the floor, and use negative
++ *            values to target a point on the ceiling.
++ *   movedir: if target is not set, this * speed * 10 is the velocity to be reached.
++ */
++#ifdef SVQC
++void spawnfunc_trigger_push();
++
++void spawnfunc_target_push();
++void spawnfunc_info_notnull();
++void spawnfunc_target_position();
++#endif
++#endif
index 1034d5d,0000000..f14b75c
mode 100644,000000..100644
--- /dev/null
@@@ -1,204 -1,0 +1,204 @@@
-       magicear_matched = FALSE;
 +#ifdef SVQC
 +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 = TRUE;
++      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;
++              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
 +}
 +#endif
index 48dc360,0000000..267c69a
mode 100644,000000..100644
--- /dev/null
@@@ -1,75 -1,0 +1,85 @@@
++#if defined(CSQC)
++#elif defined(MENUQC)
++#elif defined(SVQC)
++      #include "../../..//dpdefs/progsdefs.qh"
++    #include "../../util.qh"
++    #include "../../../server/defs.qh"
++    #include "secret.qh"
++#endif
++
 +#ifdef SVQC
++
 +void secrets_setstatus() {
 +      self.stat_secrets_total = secrets_total;
 +      self.stat_secrets_found = secrets_found;
 +}
 +
 +/**
 + * A secret has been found (maybe :P)
 + */
 +void trigger_secret_touch() {
 +      // only a player can trigger this
 +      if (!IS_PLAYER(other))
 +              return;
 +
 +      // update secrets found counter
 +      secrets_found += 1;
 +      //print("Secret found: ", ftos(secret_counter.cnt), "/");
 +      //print(ftos(secret_counter.count), "\n");
 +
 +      // centerprint message (multi_touch() doesn't always call centerprint())
 +      centerprint(other, self.message);
 +      self.message = "";
 +
 +      // handle normal trigger features
 +      multi_touch();
 +      remove(self);
 +}
 +
 +/*QUAKED trigger_secret (.5 .5 .5) ?
 +Variable sized secret trigger. Can be targeted at one or more entities.
 +Basically, it's a trigger_once (with restrictions, see notes) that additionally updates the number of secrets found.
 +-------- KEYS --------
 +sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (default: 1)
 +noise: path to sound file, if you want to play something else
 +target: trigger all entities with this targetname when triggered
 +message: print this message to the player who activated the trigger instead of the standard 'You found a secret!'
 +killtarget: remove all entities with this targetname when triggered
 +-------- NOTES --------
 +You should create a common/trigger textured brush covering the entrance to a secret room/area.
 +Trigger secret can only be trigger by a player's touch and can not be a target itself.
 +*/
 +void spawnfunc_trigger_secret() {
 +      // FIXME: should it be disabled in most modes?
 +
 +      // update secrets count
 +      secrets_total += 1;
 +
 +      // add default message
 +      if (self.message == "")
 +              self.message = "You found a secret!";
 +
 +      // set default sound
 +      if (self.noise == "")
 +      if (!self.sounds)
 +              self.sounds = 1; // misc/secret.wav
 +
 +      // this entity can't be a target itself!!!!
 +      self.targetname = "";
 +
 +      // you can't just shoot a room to find it, can you?
 +      self.health = 0;
 +
 +      // a secret can not be delayed
 +      self.delay = 0;
 +
 +      // convert this trigger to trigger_once
 +      self.classname = "trigger_once";
 +      spawnfunc_trigger_once();
 +
 +      // take over the touch() function, so we can mark secret as found
 +      self.touch = trigger_secret_touch;
 +      // ignore triggering;
 +      self.use = func_null;
 +}
 +#endif
index e289f57,0000000..c09da6b
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,24 @@@
++#ifndef SECRET_H
++#define SECRET_H
 +#ifdef SVQC
++
 +/**
 + * Total number of secrets on the map.
 + */
 +float secrets_total;
 +
 +/**
 + * Total numbe of secrets found on the map.
 + */
 +float secrets_found;
 +
 +
 +.float stat_secrets_total;
 +.float stat_secrets_found;
 +
 +/**
 + * update secrets status.
 + */
 +void secrets_setstatus();
 +#endif
++#endif
index a13aa67,0000000..474eb24
mode 100644,000000..100644
--- /dev/null
@@@ -1,170 -1,0 +1,192 @@@
-       return TRUE;
++#if defined(CSQC)
++#elif defined(MENUQC)
++#elif defined(SVQC)
++      #include "../../../dpdefs/progsdefs.qh"
++    #include "../../../warpzonelib/util_server.qh"
++    #include "../../weapons/weapons.qh"
++    #include "../../../server/defs.qh"
++    #include "../../deathtypes.qh"
++#endif
++
++/*
++*             t_swamp.c
++*             Adds spawnfunc_trigger_swamp and suppoart routines for xonotic 1.2.1+
++*             Author tZork (Jakob MG)
++*             jakob@games43.se
++*             2005 11 29
++*/
++
++.float swamp_interval;        //Hurt players in swamp with this interval
++.float swamp_slowdown;        //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
++.entity swampslug;
++
 +#ifdef SVQC
 +void spawnfunc_trigger_swamp(void);
 +#endif
 +void swamp_touch(void);
 +void swampslug_think();
 +
 +
 +/*
 +* Uses a entity calld swampslug to handle players in the swamp
 +* It works like this: When the plyer enters teh swamp the spawnfunc_trigger_swamp
 +* attaches a new "swampslug" to the player. As long as the plyer is inside
 +* the swamp the swamp gives the slug new health. But the slug slowly kills itself
 +* so when the player goes outside the swamp, it dies and releases the player from the
 +* swamps curses (dmg/slowdown)
 +*
 +* I do it this way becuz there is no "untouch" event.
 +*/
 +void swampslug_think(void)
 +{
 +      //Slowly kill the slug
 +      self.health = self.health - 1;
 +
 +      //Slug dead? then remove curses.
 +      if(self.health <= 0)
 +      {
 +              self.owner.in_swamp = 0;
 +              remove(self);
 +              //centerprint(self.owner,"Killing slug...\n");
 +              return;
 +      }
 +
 +      // Slug still alive, so we are still in the swamp
 +      // Or we have exited it very recently.
 +      // Do the damage and renew the timer.
 +#ifdef SVQC
 +      Damage (self.owner, self, self, self.dmg, DEATH_SWAMP, other.origin, '0 0 0');
 +#endif
 +
 +      self.nextthink = time + self.swamp_interval;
 +}
 +
 +void swamp_touch(void)
 +{
 +      // If whatever thats touching the swamp is not a player
 +      // or if its a dead player, just dont care abt it.
 +      if(!IS_PLAYER(other) || PHYS_DEAD(other))
 +              return;
 +
 +      EXACTTRIGGER_TOUCH;
 +
 +      // Chech if player alredy got a swampslug.
 +      if(other.in_swamp != 1)
 +      {
 +              // If not attach one.
 +              //centerprint(other,"Entering swamp!\n");
 +              other.swampslug = spawn();
 +              other.swampslug.health = 2;
 +              other.swampslug.think = swampslug_think;
 +              other.swampslug.nextthink = time;
 +              other.swampslug.owner = other;
 +              other.swampslug.dmg = self.dmg;
 +              other.swampslug.swamp_interval = self.swamp_interval;
 +              other.swamp_slowdown = self.swamp_slowdown;
 +              other.in_swamp = 1;
 +              return;
 +      }
 +
 +      //other.in_swamp = 1;
 +
 +      //Revitalize players swampslug
 +      other.swampslug.health = 2;
 +}
 +
 +#ifdef SVQC
 +float swamp_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_LADDER);
 +
 +      WriteByte(MSG_ENTITY, self.warpzone_isboxy);
 +      WriteByte(MSG_ENTITY, self.scale);
 +      WriteByte(MSG_ENTITY, self.dmg); // can probably get away with using a single byte here
 +      WriteByte(MSG_ENTITY, self.swamp_slowdown);
 +      WriteByte(MSG_ENTITY, self.swamp_interval);
 +      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);
 +
 +      WriteAngle(MSG_ENTITY, self.angles_x);
 +      WriteAngle(MSG_ENTITY, self.angles_y);
 +      WriteAngle(MSG_ENTITY, self.angles_z);
 +
-       Net_LinkEntity(self, FALSE, 0, func_ladder_send);
++      return true;
 +}
 +
 +void swamp_link()
 +{
++      Net_LinkEntity(self, false, 0, func_ladder_send);
 +}
 +
 +/*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ?
 +Players gettin into the swamp will
 +get slowd down and damaged
 +*/
 +void spawnfunc_trigger_swamp(void)
 +{
 +      // Init stuff
 +      EXACTTRIGGER_INIT;
 +      self.touch = swamp_touch;
 +
 +      // Setup default keys, if missing
 +      if(self.dmg <= 0)
 +              self.dmg = 5;
 +      if(self.swamp_interval <= 0)
 +              self.swamp_interval = 1;
 +      if(self.swamp_slowdown <= 0)
 +              self.swamp_slowdown = 0.5;
 +
 +      swamp_link();
 +}
 +
 +#elif defined(CSQC)
 +
 +void ent_swamp()
 +{
 +      self.warpzone_isboxy = ReadByte();
 +      self.scale = ReadByte();
 +      self.dmg = ReadByte();
 +      self.swamp_slowdown = ReadByte();
 +      self.swamp_interval = 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 = ReadAngle();
 +      self.angles_y = ReadAngle();
 +      self.angles_z = ReadAngle();
 +
 +      self.classname = "trigger_swamp";
 +      self.solid = SOLID_TRIGGER;
 +      self.draw = trigger_draw_generic;
 +      self.trigger_touch = swamp_touch;
 +      self.drawmask = MASK_NORMAL;
 +      self.move_time = time;
 +}
 +#endif
index c58ac5f,0000000..86b1431
mode 100644,000000..100644
--- /dev/null
@@@ -1,10 -1,0 +1,15 @@@
++#ifndef TRIGGER_SWAMP_H
++#define TRIGGER_SWAMP_H
++
 +.float swamp_interval;        //Hurt players in swamp with this interval
 +.float swamp_slowdown;        //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
 +.entity swampslug;
 +
 +.float in_swamp;              // bool
 +.entity swampslug;            // Uses this to release from swamp ("untouch" fix)
 +
 +#ifdef CSQC
 +void ent_swamp();
 +#endif
++
++#endif
index 68eaf1a,0000000..d1a5ea3
mode 100644,000000..100644
--- /dev/null
@@@ -1,43 -1,0 +1,54 @@@
- #define ACTIVE_NOT            0
- #define ACTIVE_ACTIVE         1
- #define ACTIVE_IDLE   2
- #define ACTIVE_BUSY   2
- #define ACTIVE_TOGGLE 3
++#ifndef TRIGGERS_H
++#define TRIGGERS_H
++
 +const float SF_TRIGGER_INIT = 1;
 +const float SF_TRIGGER_UPDATE = 2;
 +const float SF_TRIGGER_RESET = 4;
 +
 +const float   SPAWNFLAG_NOMESSAGE = 1;
 +const float   SPAWNFLAG_NOTOUCH = 1;
 +
 +.void() trigger_touch;
 +
 +.float height;
 +
 +.float nottargeted;
 +#define IFTARGETED if(!self.nottargeted && self.targetname != "")
 +
 +.string bgmscript;
 +.float bgmscriptattack;
 +.float bgmscriptdecay;
 +.float bgmscriptsustain;
 +.float bgmscriptrelease;
 +
++.float lip;
++
 +// used elsewhere (will fix)
 +#ifdef SVQC
 +void spawnfunc_trigger_once();
 +string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin);
 +
 +void target_voicescript_next(entity pl);
 +void target_voicescript_clear(entity pl);
 +#endif
 +
 +.float volume, atten;
 +
 +.vector dest;
 +
 +#ifdef CSQC
++float WarpZoneLib_ExactTrigger_Touch();
++#define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
++
 +.float active;
 +.string target;
 +.string targetname;
++
++const int ACTIVE_NOT          = 0;
++const int ACTIVE_ACTIVE       = 1;
++const int ACTIVE_IDLE                 = 2;
++const int ACTIVE_BUSY                 = 2;
++const int ACTIVE_TOGGLE               = 3;
++#endif
++
 +#endif
@@@ -38,6 -38,6 +38,8 @@@ PORTO_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PR
  #endif
  #else
  #ifdef SVQC
++#include "../triggers/trigger/jumppads.qh"
++
  void spawnfunc_weapon_porto(void) { weapon_defaultspawnfunc(WEP_PORTO); }
  
  void W_Porto_Success(void)
@@@ -2,6 -2,6 +2,7 @@@
  #include "role_onslaught.qc"
  #include "role_keyhunt.qc"
  #include "roles.qc"
++#include "../../../common/triggers/trigger/jumppads.qh"
  
  void havocbot_ai()
  {