void plat_spawn_inside_trigger()
{
- local entity trigger;
- local vector tmin, tmax;
+ entity trigger;
+ vector tmin, tmax;
trigger = spawn();
trigger.touch = plat_center_touch;
tmax_y = tmin_y + 1;
}
- setsize (trigger, tmin, tmax);
-};
+ if(tmin_x < tmax_x)
+ if(tmin_y < tmax_y)
+ if(tmin_z < tmax_z)
+ {
+ setsize (trigger, tmin, tmax);
+ return;
+ }
+
+ // otherwise, something is fishy...
+ remove(trigger);
+ objerror("plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
+}
void plat_hit_top()
{
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);
self.state = 2;
-};
+}
void plat_go_down()
{
sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_NORM);
self.state = 3;
SUB_CalcMove (self.pos2, self.speed, plat_hit_bottom);
-};
+}
void plat_go_up()
{
sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_NORM);
self.state = 4;
SUB_CalcMove (self.pos1, self.speed, plat_hit_top);
-};
+}
void plat_center_touch()
{
plat_go_up ();
else if (self.state == 1)
self.nextthink = self.ltime + 1; // delay going down
-};
+}
void plat_outside_touch()
{
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()
// plat state already had changed
// this isn't a bug per se!
}
-};
+}
void plat_use()
{
if (self.state != 4)
objerror ("plat_use: not in up state");
plat_go_down();
-};
+}
.string sound1, sound2;
}
}
-void spawnfunc_path_corner() { };
+void spawnfunc_path_corner() { }
void spawnfunc_func_plat()
{
- if (!self.t_length)
- self.t_length = 80;
- if (!self.t_width)
- self.t_width = 10;
-
if (self.sounds == 0)
self.sounds = 2;
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.size_z + 8;
-
- plat_spawn_inside_trigger (); // the "start moving" trigger
+ self.pos2_z = self.origin_z - self.height;
self.reset = plat_reset;
plat_reset();
-};
+
+ plat_spawn_inside_trigger (); // the "start moving" trigger
+}
void() train_next;
SUB_UseTargets();
self = oldself;
self.enemy = world;
-};
+}
void train_next()
{
- local entity targ;
+ entity targ;
targ = find(world, targetname, self.target);
self.enemy = targ;
self.target = targ.target;
if(self.noise != "")
sound(self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_IDLE);
-};
+}
void func_train_find()
{
- local entity targ;
+ entity targ;
targ = find(world, targetname, self.target);
self.target = targ.target;
if (!self.target)
setorigin(self, targ.origin - self.mins);
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.
self.dmgtime2 = time;
// TODO make a reset function for this one
-};
+}
void func_rotating_setactive(float astate)
{
self.think = SUB_Null;
// TODO make a reset function for this one
-};
+}
.float height;
void func_bobbing_controller_think()
{
- local vector v;
+ vector v;
self.nextthink = time + 0.1;
if not (self.owner.active == ACTIVE_ACTIVE)
if(self.owner.classname == "func_bobbing") // don't brake stuff if the func_bobbing was killtarget'ed
// * 10 so it will arrive in 0.1 sec
self.owner.velocity = (v - self.owner.origin) * 10;
-};
+}
/*QUAKED spawnfunc_func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
Brush model that moves back and forth on one axis (default Z).
*/
void spawnfunc_func_bobbing()
{
- local entity controller;
+ entity controller;
if (self.noise != "")
{
precache_sound(self.noise);
self.effects |= EF_LOWPRECISION;
// TODO make a reset function for this one
-};
+}
.float freq;
void func_pendulum_controller_think()
{
- local float v;
+ float v;
self.nextthink = time + 0.1;
if not (self.owner.active == ACTIVE_ACTIVE)
// * 10 so it will arrive in 0.1 sec
self.owner.avelocity_z = (remainder(v - self.owner.angles_z, 360)) * 10;
}
-};
+}
void spawnfunc_func_pendulum()
{
- local entity controller;
+ entity controller;
if (self.noise != "")
{
precache_sound(self.noise);
//self.effects |= EF_LOWPRECISION;
// TODO make a reset function for this one
-};
+}
// button and multiple button
activator = self.enemy;
SUB_UseTargets();
self.frame = 1; // use alternate textures
-};
+}
void button_done()
{
self.state = STATE_BOTTOM;
-};
+}
void button_return()
{
self.frame = 0; // use normal textures
if (self.health)
self.takedamage = DAMAGE_YES; // can be shot again
-};
+}
void button_blocked()
{
// do nothing, just don't come all the way back out
-};
+}
void button_fire()
self.state = STATE_UP;
SUB_CalcMove (self.pos2, self.speed, button_wait);
-};
+}
void button_reset()
{
self.enemy = activator;
button_fire ();
-};
+}
void button_touch()
{
if (other.owner)
self.enemy = other.owner;
button_fire ();
-};
+}
void button_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
{
self.enemy = damage_attacker;
button_fire ();
}
-};
+}
/*QUAKED spawnfunc_func_button (0 .5 .8) ?
self.flags |= FL_NOTARGET;
button_reset();
-};
+}
float DOOR_START_OPEN = 1;
door_go_down ();
}
*/
-};
+}
void door_hit_top()
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, ATTN_NORM);
self.state = STATE_BOTTOM;
-};
+}
void door_go_down()
{
self.state = STATE_DOWN;
SUB_CalcMove (self.pos1, self.speed, door_hit_bottom);
-};
+}
void door_go_up()
{
self.message = "";
SUB_UseTargets();
self.message = oldmessage;
-};
+}
*/
float door_check_keys(void) {
- local entity door, p;
+ local entity door;
if (self.owner)
else
door = self;
- if (other.owner)
- p = other.owner;
- else
- p = other;
-
- if (door.spawnflags & (SPAWNFLAGS_GOLD_KEY | SPAWNFLAGS_SILVER_KEY)) {
- // this door require a key
- // only a player can have a key
- if (p.classname != "player")
- return FALSE;
-
- // check gold key
- if (self.owner.spawnflags & SPAWNFLAGS_GOLD_KEY) {
- if (!(other.itemkeys & KEYS_GOLD_KEY)) {
- if (p.key_door_messagetime <= time) {
- play2(other, "misc/talk.wav");
- centerprint(other, "You don't have the gold key!");
- p.key_door_messagetime = time + 2;
- }
- return FALSE;
- } else {
- self.owner.spawnflags &~= SPAWNFLAGS_GOLD_KEY;
- }
+ // no key needed
+ if not(door.itemkeys)
+ return TRUE;
+
+ // this door require a key
+ // only a player can have a key
+ if (other.classname != "player")
+ 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), "!"));
+ other.key_door_messagetime = time + 2;
}
-
- // check silver key
- if (self.owner.spawnflags & SPAWNFLAGS_SILVER_KEY) {
- if (!(other.itemkeys & KEYS_SILVER_KEY)) {
- if (p.key_door_messagetime <= time) {
- play2(other, "misc/talk.wav");
- centerprint(other, "You don't have the silver key!");
- p.wait = p.key_door_messagetime + 2;
- }
- return FALSE;
- } else {
- self.owner.spawnflags &~= SPAWNFLAGS_SILVER_KEY;
- }
+ } 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), "!"));
+ other.key_door_messagetime = time + 2;
}
-
+ }
+
+ if (door.itemkeys) {
// door is now unlocked
play2(other, "misc/talk.wav");
centerprint(other, "Door unlocked!");
- }
-
- return TRUE;
+ return TRUE;
+ } else
+ return FALSE;
}
void door_fire()
{
- local entity oself;
- local entity starte;
+ entity oself;
+ entity starte;
if (self.owner != self)
objerror ("door_fire: self.owner != self");
self = self.enemy;
} while ( (self != starte) && (self != world) );
self = oself;
-};
+}
void door_use()
{
- local entity oself;
+ entity oself;
//dprint("door_use (model: ");dprint(self.model);dprint(")\n");
door_fire ();
self = oself;
}
-};
+}
void door_trigger_touch()
self = self.owner;
door_use ();
-};
+}
void door_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
{
- local entity oself;
+ entity oself;
if(self.spawnflags & DOOR_NOSPLASH)
if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
return;
self.health = self.health - damage;
- if (self.spawnflags & SPAWNFLAGS_GOLD_KEY || self.spawnflags & SPAWNFLAGS_SILVER_KEY) {
+ if (self.itemkeys) {
// don't allow opening doors through damage if keys are required
return;
}
door_use ();
self = oself;
}
-};
+}
/*
centerprint (other, self.owner.message);
play2(other, "misc/talk.wav");
}
-};
+}
void door_generic_plat_blocked()
door_rotating_go_down ();
}
*/
-};
+}
void door_rotating_hit_top()
return; // don't come down automatically
self.think = door_rotating_go_down;
self.nextthink = self.ltime + self.wait;
-};
+}
void door_rotating_hit_bottom()
{
self.lip = 0;
}
self.state = STATE_BOTTOM;
-};
+}
void door_rotating_go_down()
{
self.state = STATE_DOWN;
SUB_CalcAngleMove (self.pos1, self.speed, door_rotating_hit_bottom);
-};
+}
void door_rotating_go_up()
{
self.message = "";
SUB_UseTargets();
self.message = oldmessage;
-};
+}
entity spawn_field(vector fmins, vector fmaxs)
{
- local entity trigger;
- local vector t1, t2;
+ entity trigger;
+ vector t1, t2;
trigger = spawn();
trigger.classname = "doortriggerfield";
t2 = fmaxs;
setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
return (trigger);
-};
+}
float EntitiesTouching(entity e1, entity e2)
if (e1.absmax_z < e2.absmin_z)
return FALSE;
return TRUE;
-};
+}
/*
*/
void LinkDoors()
{
- local entity t, starte;
- local vector cmins, cmaxs;
+ entity t, starte;
+ vector cmins, cmaxs;
if (self.enemy)
return; // already linked by another door
}
} while (1 );
-};
+}
/*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
self.think = SUB_Null;
}
+// spawnflags require key (for now only func_door)
+#define SPAWNFLAGS_GOLD_KEY 8
+#define SPAWNFLAGS_SILVER_KEY 16
void spawnfunc_func_door()
{
- print("spawnfunc_func_door() spawnflags=", ftos(self.spawnflags));
- print(", gold_key=", ftos(self.spawnflags & SPAWNFLAGS_GOLD_KEY));
- print(", silver_key=", ftos(self.spawnflags & SPAWNFLAGS_SILVER_KEY), "\n");
-
+ // 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);
+
//if (!self.deathtype) // map makers can override this
// self.deathtype = " got in the way";
SetMovedir ();
InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
self.reset = door_reset;
-};
+}
/*QUAKED spawnfunc_func_door_rotating (0 .5 .8) ? START_OPEN BIDIR DOOR_DONT_LINK BIDIR_IN_DOWN x TOGGLE X_AXIS Y_AXIS
if two doors touch, they are assumed to be connected and operate as a unit.
InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
self.reset = door_rotating_reset;
-};
+}
/*
=============================================================================
void fd_secret_use()
{
- local float temp;
+ float temp;
string message_save;
self.health = 10000;
SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
if (self.noise2 != "")
sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
-};
+}
// Wait after first movement...
void fd_secret_move1()
self.think = fd_secret_move2;
if (self.noise3 != "")
sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_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);
-};
+}
// Wait here until time to go back...
void fd_secret_move3()
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, ATTN_NORM);
SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
-};
+}
// Wait 1 second...
void fd_secret_move5()
self.think = fd_secret_move6;
if (self.noise3 != "")
sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_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);
-};
+}
void fd_secret_done()
{
}
if (self.noise3 != "")
sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_NORM);
-};
+}
void secret_blocked()
{
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);
-};
+}
/*
==============
centerprint (other, self.message);
play2(other, "misc/talk.wav");
}
-};
+}
void secret_reset()
{
self.reset = secret_reset;
secret_reset();
-};
+}
/*QUAKED spawnfunc_func_fourier (0 .5 .8) ?
Brush model that moves in a pattern of added up sine waves, can be used e.g. for circular motions.
void func_fourier_controller_think()
{
- local vector v;
+ vector v;
float n, i, t;
self.nextthink = time + 0.1;
if(self.owner.classname == "func_fourier") // don't brake stuff if the func_fourier was killtarget'ed
// * 10 so it will arrive in 0.1 sec
self.owner.velocity = (v - self.owner.origin) * 10;
-};
+}
void spawnfunc_func_fourier()
{
- local entity controller;
+ entity controller;
if (self.noise != "")
{
precache_sound(self.noise);
self.effects |= EF_LOWPRECISION;
// TODO make a reset function for this one
-};
+}
// reusing some fields havocbots declared
.entity wp00, wp01, wp02, wp03;
self.destvec = self.origin - func_vectormamamam_origin(self.owner, 0);
- local entity controller;
+ entity controller;
controller = spawn();
controller.classname = "func_vectormamamam_controller";
controller.owner = self;
InitializeEntity(self, func_vectormamamam_findtarget, INITPRIO_FINDTARGET);
}
+
+void conveyor_think()
+{
+ 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); 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(e.flags & FL_CLIENT) // doing it via velocity has quite some advantages
+ continue; // done in SV_PlayerPhysics
+
+ setorigin(e, e.origin + self.movedir * sys_frametime);
+ move_out_of_solid(e);
+ UpdateCSQCProjectile(e);
+ /*
+ // 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);
+ */
+ }
+ }
+
+ self.nextthink = time;
+}
+
+void conveyor_use()
+{
+ self.state = !self.state;
+}
+
+void conveyor_reset()
+{
+ self.state = (self.spawnflags & 1);
+}
+
+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;
+}
+
+void spawnfunc_trigger_conveyor()
+{
+ SetMovedir();
+ EXACTTRIGGER_INIT;
+ conveyor_init();
+}
+
+void spawnfunc_func_conveyor()
+{
+ SetMovedir();
+ InitMovingBrushTrigger();
+ self.movetype = MOVETYPE_NONE;
+ conveyor_init();
+}