]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/t_plats.qc
Some random fixes and stuff (centerprints converted to notifications, less spam when...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / t_plats.qc
index 24da476d72bad18cb5d19089a883492b98d392c5..d3f72b7ebc4bdad9355cf89b6462e6d10b93f2da 100644 (file)
@@ -83,19 +83,19 @@ void plat_go_down()
 {
        sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
        self.state = 3;
-       SUB_CalcMove (self.pos2, self.speed, plat_hit_bottom);
+       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, self.speed, plat_hit_top);
+       SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, plat_hit_top);
 }
 
 void plat_center_touch()
 {
-       if not(other.iscreature)
+       if (!other.iscreature)
                return;
 
        if (other.health <= 0)
@@ -110,7 +110,7 @@ void plat_center_touch()
 
 void plat_outside_touch()
 {
-       if not(other.iscreature)
+       if (!other.iscreature)
                return;
 
        if (other.health <= 0)
@@ -177,7 +177,43 @@ void plat_reset()
        }
 }
 
-void spawnfunc_path_corner() { }
+.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 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 FALSE;
+       }
+
+       return TRUE;
+}
+
+void spawnfunc_path_corner()
+{
+       // setup values for overriding train movement
+       // if a second value does not exist, both start and end speeds are the single value specified
+       if(!set_platmovetype(self, self.platmovetype))
+               return;
+}
 void spawnfunc_func_plat()
 {
        if (self.sounds == 0)
@@ -222,7 +258,7 @@ void spawnfunc_func_plat()
        self.angles = '0 0 0';
 
        self.classname = "plat";
-       if not(InitMovingBrushTrigger())
+       if (!InitMovingBrushTrigger())
                return;
        self.effects |= EF_LOWPRECISION;
        setsize (self, self.mins , self.maxs);
@@ -246,15 +282,49 @@ void spawnfunc_func_plat()
        plat_spawn_inside_trigger ();   // the "start moving" trigger
 }
 
-
+.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 = 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)
+       if(self.wait < 0 || self.train_wait_turning) // no waiting or we already waited while turning
        {
+               self.train_wait_turning = FALSE;
                train_next();
        }
        else
@@ -262,31 +332,56 @@ void train_wait()
                self.think = train_next;
                self.nextthink = self.ltime + self.wait;
        }
-
-       entity oldself;
-       oldself = self;
-       self = self.enemy;
-       SUB_UseTargets();
-       self = oldself;
-       self.enemy = world;
 }
 
 void train_next()
 {
-       entity targ;
+       entity targ, cp = world;
+       vector cp_org = '0 0 0';
+
        targ = find(world, targetname, self.target);
-       self.enemy = targ;
        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)
-               SUB_CalcMove(targ.origin - self.mins, targ.speed, train_wait);
+       {
+               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
-               SUB_CalcMove(targ.origin - self.mins, self.speed, train_wait);
+       {
+               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);
@@ -299,7 +394,7 @@ void func_train_find()
        self.target = targ.target;
        if (self.target == "")
                objerror("func_train_find: no next target");
-       setorigin(self, targ.origin - self.mins);
+       setorigin(self, targ.origin - self.view_ofs);
        self.nextthink = self.ltime + 1;
        self.think = train_next;
 }
@@ -319,9 +414,17 @@ void spawnfunc_func_train()
        if (!self.speed)
                self.speed = 100;
 
-       if not(InitMovingBrushTrigger())
+       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);
@@ -335,14 +438,19 @@ void spawnfunc_func_train()
                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
 }
 
 void func_rotating_setactive(float astate)
 {
-       
+
        if (astate == ACTIVE_TOGGLE)
-       {               
+       {
                if(self.active == ACTIVE_ACTIVE)
                        self.active = ACTIVE_NOT;
                else
@@ -350,8 +458,8 @@ void func_rotating_setactive(float astate)
        }
        else
                self.active = astate;
-               
-       if(self.active  == ACTIVE_NOT)          
+
+       if(self.active  == ACTIVE_NOT)
                self.avelocity = '0 0 0';
        else
                self.avelocity = self.pos1;
@@ -372,10 +480,10 @@ void spawnfunc_func_rotating()
                precache_sound(self.noise);
                ambientsound(self.origin, self.noise, VOL_BASE, ATTEN_IDLE);
        }
-       
+
        self.active = ACTIVE_ACTIVE;
        self.setactive = func_rotating_setactive;
-       
+
        if (!self.speed)
                self.speed = 100;
        // FIXME: test if this turns the right way, then remove this comment (negate as needed)
@@ -387,9 +495,9 @@ void spawnfunc_func_rotating()
        // FIXME: test if this turns the right way, then remove this comment (negate as needed)
        else // Z
                self.avelocity = '0 1 0' * self.speed;
-       
+
        self.pos1 = self.avelocity;
-    
+
     if(self.dmg && (self.message == ""))
         self.message = " was squished";
     if(self.dmg && (self.message2 == ""))
@@ -401,7 +509,7 @@ void spawnfunc_func_rotating()
 
     self.dmgtime2 = time;
 
-       if not(InitMovingBrushTrigger())
+       if (!InitMovingBrushTrigger())
                return;
        // no EF_LOWPRECISION here, as rounding angles is bad
 
@@ -419,13 +527,13 @@ void func_bobbing_controller_think()
 {
        vector v;
        self.nextthink = time + 0.1;
-       
-       if not (self.owner.active == ACTIVE_ACTIVE)
+
+       if(self.owner.active != ACTIVE_ACTIVE)
        {
-               self.owner.velocity = '0 0 0';          
+               self.owner.velocity = '0 0 0';
                return;
        }
-               
+
        // calculate sinewave using makevectors
        makevectors((self.nextthink * self.owner.cnt + self.owner.phase * 360) * '0 1 0');
        v = self.owner.destvec + self.owner.movedir * v_forward_y;
@@ -480,7 +588,7 @@ void spawnfunc_func_bobbing()
        else // Z
                self.movedir = '0 0 1' * self.height;
 
-       if not(InitMovingBrushTrigger())
+       if (!InitMovingBrushTrigger())
                return;
 
        // wait for targets to spawn
@@ -504,7 +612,7 @@ void func_pendulum_controller_think()
        float v;
        self.nextthink = time + 0.1;
 
-       if not (self.owner.active == ACTIVE_ACTIVE)
+       if (!(self.owner.active == ACTIVE_ACTIVE))
        {
                self.owner.avelocity_x = 0;
                return;
@@ -548,7 +656,7 @@ void spawnfunc_func_pendulum()
        self.blocked = generic_plat_blocked;
 
        self.avelocity_z = 0.0000001;
-       if not(InitMovingBrushTrigger())
+       if (!InitMovingBrushTrigger())
                return;
 
        if(!self.freq)
@@ -597,7 +705,7 @@ void button_done()
 void button_return()
 {
        self.state = STATE_DOWN;
-       SUB_CalcMove (self.pos1, self.speed, button_done);
+       SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, button_done);
        self.frame = 0;                 // use normal textures
        if (self.health)
                self.takedamage = DAMAGE_YES;   // can be shot again
@@ -622,7 +730,7 @@ void button_fire()
                sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
 
        self.state = STATE_UP;
-       SUB_CalcMove (self.pos2, self.speed, button_wait);
+       SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, button_wait);
 }
 
 void button_reset()
@@ -637,7 +745,7 @@ void button_reset()
 
 void button_use()
 {
-       if not (self.active == ACTIVE_ACTIVE)
+       if(self.active != ACTIVE_ACTIVE)
                return;
 
        self.enemy = activator;
@@ -648,7 +756,7 @@ void button_touch()
 {
        if (!other)
                return;
-       if not(other.iscreature)
+       if (!other.iscreature)
                return;
        if(other.velocity * self.movedir < 0)
                return;
@@ -691,7 +799,7 @@ void spawnfunc_func_button()
 {
        SetMovedir ();
 
-       if not(InitMovingBrushTrigger())
+       if (!InitMovingBrushTrigger())
                return;
        self.effects |= EF_LOWPRECISION;
 
@@ -846,7 +954,7 @@ void door_go_down()
        }
 
        self.state = STATE_DOWN;
-       SUB_CalcMove (self.pos1, self.speed, door_hit_bottom);
+       SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, door_hit_bottom);
 }
 
 void door_go_up()
@@ -863,7 +971,7 @@ void door_go_up()
        if (self.noise2 != "")
                sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
        self.state = STATE_UP;
-       SUB_CalcMove (self.pos2, self.speed, door_hit_top);
+       SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, door_hit_top);
 
        string oldmessage;
        oldmessage = self.message;
@@ -884,34 +992,34 @@ ACTIVATION FUNCTIONS
 
 float door_check_keys(void) {
        local entity door;
-       
-       
+
+
        if (self.owner)
                door = self.owner;
        else
                door = self;
-       
+
        // no key needed
-       if not(door.itemkeys)
+       if (!door.itemkeys)
                return TRUE;
 
        // this door require a key
        // only a player can have a key
-       if not(IS_PLAYER(other))
+       if (!IS_PLAYER(other))
                return FALSE;
-       
+
        if (item_keys_usekey(door, other)) {
                // some keys were used
                if (other.key_door_messagetime <= time) {
                        play2(other, "misc/talk.wav");
-                       centerprint(other, strcat("You also need ", item_keys_keylist(door.itemkeys), "!"));
+                       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");
-                       centerprint(other, strcat("You need ", item_keys_keylist(door.itemkeys), "!"));
+                       Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(door.itemkeys));
                        other.key_door_messagetime = time + 2;
                }
        }
@@ -919,7 +1027,7 @@ float door_check_keys(void) {
        if (door.itemkeys) {
                // door is now unlocked
                play2(other, "misc/talk.wav");
-               centerprint(other, "Door unlocked!");
+               Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_UNLOCKED);
                return TRUE;
        } else
                return FALSE;
@@ -991,7 +1099,7 @@ void door_use()
        entity oself;
 
        //dprint("door_use (model: ");dprint(self.model);dprint(")\n");
-       
+
        if (self.owner)
        {
                oself = self;
@@ -1005,16 +1113,16 @@ void door_use()
 void door_trigger_touch()
 {
        if (other.health < 1)
-               if not(other.iscreature && other.deadflag == DEAD_NO)
+               if (!(other.iscreature && other.deadflag == DEAD_NO))
                        return;
 
        if (time < self.attack_finished_single)
                return;
-       
+
        // check if door is locked
        if (!door_check_keys())
                return;
-       
+
        self.attack_finished_single = time + 1;
 
        activator = other;
@@ -1031,12 +1139,12 @@ void door_damage(entity inflictor, entity attacker, float damage, float deathtyp
                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;
@@ -1058,7 +1166,7 @@ Prints messages
 */
 void door_touch()
 {
-       if not(IS_PLAYER(other))
+       if (!IS_PLAYER(other))
                return;
        if (self.owner.attack_finished_single > time)
                return;
@@ -1148,7 +1256,7 @@ void door_rotating_go_down()
        }
 
        self.state = STATE_DOWN;
-       SUB_CalcAngleMove (self.pos1, self.speed, door_rotating_hit_bottom);
+       SUB_CalcAngleMove (self.pos1, TSPEED_LINEAR, self.speed, door_rotating_hit_bottom);
 }
 
 void door_rotating_go_up()
@@ -1164,7 +1272,7 @@ void door_rotating_go_up()
        if (self.noise2 != "")
                sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
        self.state = STATE_UP;
-       SUB_CalcAngleMove (self.pos2, self.speed, door_rotating_hit_top);
+       SUB_CalcAngleMove (self.pos2, TSPEED_LINEAR, self.speed, door_rotating_hit_top);
 
        string oldmessage;
        oldmessage = self.message;
@@ -1381,13 +1489,13 @@ void spawnfunc_func_door()
                self.itemkeys |= ITEM_KEY_BIT(0);
        if (self.spawnflags & SPAWNFLAGS_SILVER_KEY)
                self.itemkeys |= ITEM_KEY_BIT(1);
-               
+
        //if (!self.deathtype) // map makers can override this
        //      self.deathtype = " got in the way";
        SetMovedir ();
 
        self.max_health = self.health;
-       if not(InitMovingBrushTrigger())
+       if (!InitMovingBrushTrigger())
                return;
        self.effects |= EF_LOWPRECISION;
        self.classname = "door";
@@ -1513,7 +1621,7 @@ void spawnfunc_func_door_rotating()
 
        self.max_health = self.health;
        self.avelocity = self.movedir;
-       if not(InitMovingBrushTrigger())
+       if (!InitMovingBrushTrigger())
                return;
        self.velocity = '0 0 0';
        //self.effects |= EF_LOWPRECISION;
@@ -1639,7 +1747,7 @@ void fd_secret_use()
                self.dest1 = self.origin + v_right * (self.t_width * temp);
 
        self.dest2 = self.dest1 + v_forward * self.t_length;
-       SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
+       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);
 }
@@ -1663,7 +1771,7 @@ void fd_secret_move2()
 {
        if (self.noise2 != "")
                sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
-       SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
+       SUB_CalcMove(self.dest2, TSPEED_LINEAR, self.speed, fd_secret_move3);
 }
 
 // Wait here until time to go back...
@@ -1683,7 +1791,7 @@ void fd_secret_move4()
 {
        if (self.noise2 != "")
                sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
-       SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
+       SUB_CalcMove(self.dest1, TSPEED_LINEAR, self.speed, fd_secret_move5);
 }
 
 // Wait 1 second...
@@ -1699,7 +1807,7 @@ void fd_secret_move6()
 {
        if (self.noise2 != "")
                sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
-       SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
+       SUB_CalcMove(self.oldorigin, TSPEED_LINEAR, self.speed, fd_secret_done);
 }
 
 void fd_secret_done()
@@ -1731,7 +1839,7 @@ Prints messages
 */
 void secret_touch()
 {
-       if not(other.iscreature)
+       if (!other.iscreature)
                return;
        if (self.attack_finished_single > time)
                return;
@@ -1787,7 +1895,7 @@ void spawnfunc_func_door_secret()
        self.mangle = self.angles;
        self.angles = '0 0 0';
        self.classname = "door";
-       if not(InitMovingBrushTrigger())
+       if (!InitMovingBrushTrigger())
                return;
        self.effects |= EF_LOWPRECISION;
 
@@ -1832,9 +1940,9 @@ void func_fourier_controller_think()
        float n, i, t;
 
        self.nextthink = time + 0.1;
-       if not (self.owner.active == ACTIVE_ACTIVE)
+       if(self.owner.active != ACTIVE_ACTIVE)
        {
-               self.owner.velocity = '0 0 0';          
+               self.owner.velocity = '0 0 0';
                return;
        }
 
@@ -1883,7 +1991,7 @@ void spawnfunc_func_fourier()
        if(self.netname == "")
                self.netname = "1 0 0 0 1";
 
-       if not(InitMovingBrushTrigger())
+       if (!InitMovingBrushTrigger())
                return;
 
        self.active = ACTIVE_ACTIVE;
@@ -1965,9 +2073,9 @@ void func_vectormamamam_controller_think()
 {
        self.nextthink = time + 0.1;
 
-       if not (self.owner.active == ACTIVE_ACTIVE)
+       if(self.owner.active != ACTIVE_ACTIVE)
        {
-               self.owner.velocity = '0 0 0';          
+               self.owner.velocity = '0 0 0';
                return;
        }
 
@@ -2046,7 +2154,7 @@ void spawnfunc_func_vectormamamam()
        if(self.netname == "")
                self.netname = "1 0 0 0 1";
 
-       if not(InitMovingBrushTrigger())
+       if (!InitMovingBrushTrigger())
                return;
 
        // wait for targets to spawn