}
-float STATE_TOP = 0;
-float STATE_BOTTOM = 1;
-float STATE_UP = 2;
-float STATE_DOWN = 3;
-
.entity trigger_field;
void() plat_center_touch;
void() plat_go_up;
void() plat_go_down;
void() plat_crush;
-float PLAT_LOW_TRIGGER = 1;
+const float PLAT_LOW_TRIGGER = 1;
void plat_spawn_inside_trigger()
{
void plat_hit_top()
{
- sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
+ 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, ATTN_NORM);
+ 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, ATTN_NORM);
+ 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, ATTN_NORM);
+ 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)
void plat_outside_touch()
{
- if not(other.iscreature)
+ if (!other.iscreature)
return;
if (other.health <= 0)
}
}
-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)
self.angles = '0 0 0';
self.classname = "plat";
- if not(InitMovingBrushTrigger())
+ if (!InitMovingBrushTrigger())
return;
self.effects |= EF_LOWPRECISION;
setsize (self, self.mins , self.maxs);
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
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, ATTN_IDLE);
+ sound(self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
}
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;
}
if (!self.speed)
self.speed = 100;
- if not(InitMovingBrushTrigger())
+ 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;
+
+ if (!InitMovingBrushTrigger())
return;
self.effects |= EF_LOWPRECISION;
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
}
if (self.noise != "")
{
precache_sound(self.noise);
- ambientsound(self.origin, self.noise, VOL_BASE, ATTN_IDLE);
+ ambientsound(self.origin, self.noise, VOL_BASE, ATTEN_IDLE);
}
self.active = ACTIVE_ACTIVE;
self.dmgtime2 = time;
- if not(InitMovingBrushTrigger())
+ if (!InitMovingBrushTrigger())
return;
// no EF_LOWPRECISION here, as rounding angles is bad
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';
return;
if (self.noise != "")
{
precache_sound(self.noise);
- soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_IDLE);
+ soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
}
if (!self.speed)
self.speed = 4;
else // Z
self.movedir = '0 0 1' * self.height;
- if not(InitMovingBrushTrigger())
+ if (!InitMovingBrushTrigger())
return;
// wait for targets to spawn
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;
if (self.noise != "")
{
precache_sound(self.noise);
- soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_IDLE);
+ soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
}
self.active = ACTIVE_ACTIVE;
self.blocked = generic_plat_blocked;
self.avelocity_z = 0.0000001;
- if not(InitMovingBrushTrigger())
+ if (!InitMovingBrushTrigger())
return;
if(!self.freq)
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
return;
if (self.noise != "")
- sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
+ 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()
void button_use()
{
- if not (self.active == ACTIVE_ACTIVE)
+ if (!(self.active == ACTIVE_ACTIVE))
return;
self.enemy = activator;
{
if (!other)
return;
- if not(other.iscreature)
+ if (!other.iscreature)
return;
if(other.velocity * self.movedir < 0)
return;
{
SetMovedir ();
- if not(InitMovingBrushTrigger())
+ if (!InitMovingBrushTrigger())
return;
self.effects |= EF_LOWPRECISION;
}
-float DOOR_START_OPEN = 1;
-float DOOR_DONT_LINK = 4;
-float DOOR_TOGGLE = 32;
+const float DOOR_START_OPEN = 1;
+const float DOOR_DONT_LINK = 4;
+const float DOOR_TOGGLE = 32;
/*
void door_hit_top()
{
if (self.noise1 != "")
- sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
+ 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
void door_hit_bottom()
{
if (self.noise1 != "")
- sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
+ 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, ATTN_NORM);
+ sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
if (self.max_health)
{
self.takedamage = DAMAGE_YES;
}
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()
}
if (self.noise2 != "")
- sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
+ 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;
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)) {
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)
*/
void door_touch()
{
- if not(IS_PLAYER(other))
+ if (!IS_PLAYER(other))
return;
if (self.owner.attack_finished_single > time)
return;
void door_rotating_hit_top()
{
if (self.noise1 != "")
- sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
+ 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
void door_rotating_hit_bottom()
{
if (self.noise1 != "")
- sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
+ 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;
void door_rotating_go_down()
{
if (self.noise2 != "")
- sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
+ sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTEN_NORM);
if (self.max_health)
{
self.takedamage = DAMAGE_YES;
}
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()
return;
}
if (self.noise2 != "")
- sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
+ 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;
SetMovedir ();
self.max_health = self.health;
- if not(InitMovingBrushTrigger())
+ if (!InitMovingBrushTrigger())
return;
self.effects |= EF_LOWPRECISION;
self.classname = "door";
self.max_health = self.health;
self.avelocity = self.movedir;
- if not(InitMovingBrushTrigger())
+ if (!InitMovingBrushTrigger())
return;
self.velocity = '0 0 0';
//self.effects |= EF_LOWPRECISION;
void() fd_secret_move6;
void() fd_secret_done;
-float SECRET_OPEN_ONCE = 1; // stays open
-float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
-float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
-float SECRET_NO_SHOOT = 8; // only opened by trigger
-float SECRET_YES_SHOOT = 16; // shootable even if targeted
+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()
{
// Make a sound, wait a little...
if (self.noise1 != "")
- sound(self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
+ 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
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, ATTN_NORM);
+ 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)
self.nextthink = self.ltime + 1.0;
self.think = fd_secret_move2;
if (self.noise3 != "")
- sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_NORM);
+ 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, ATTN_NORM);
- SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
+ 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, ATTN_NORM);
+ sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
if (!(self.spawnflags & SECRET_OPEN_ONCE))
{
self.nextthink = self.ltime + self.wait;
void fd_secret_move4()
{
if (self.noise2 != "")
- sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
- SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
+ 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...
self.nextthink = self.ltime + 1.0;
self.think = fd_secret_move6;
if (self.noise3 != "")
- sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_NORM);
+ 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, ATTN_NORM);
- SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
+ 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()
//self.th_pain = fd_secret_use;
}
if (self.noise3 != "")
- sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_NORM);
+ sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
}
void secret_blocked()
*/
void secret_touch()
{
- if not(other.iscreature)
+ if (!other.iscreature)
return;
if (self.attack_finished_single > time)
return;
self.mangle = self.angles;
self.angles = '0 0 0';
self.classname = "door";
- if not(InitMovingBrushTrigger())
+ if (!InitMovingBrushTrigger())
return;
self.effects |= EF_LOWPRECISION;
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';
return;
if (self.noise != "")
{
precache_sound(self.noise);
- soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_IDLE);
+ soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
}
if (!self.speed)
if(self.netname == "")
self.netname = "1 0 0 0 1";
- if not(InitMovingBrushTrigger())
+ if (!InitMovingBrushTrigger())
return;
self.active = ACTIVE_ACTIVE;
{
self.nextthink = time + 0.1;
- if not (self.owner.active == ACTIVE_ACTIVE)
+ if (!(self.owner.active == ACTIVE_ACTIVE))
{
self.owner.velocity = '0 0 0';
return;
if (self.noise != "")
{
precache_sound(self.noise);
- soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_IDLE);
+ soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
}
if(!self.targetfactor)
if(self.netname == "")
self.netname = "1 0 0 0 1";
- if not(InitMovingBrushTrigger())
+ if (!InitMovingBrushTrigger())
return;
// wait for targets to spawn