<zinx> taniwha: FWIW, the code is officially donated to quakeforge :)

<taniwha> zinx: thanks :)

zinx' klik mod :)
This commit is contained in:
Bill Currie 2003-10-24 21:43:32 +00:00
parent 0e88e9927a
commit 88c055ea3c
99 changed files with 10309 additions and 0 deletions

120
klik/Makefile Normal file
View file

@ -0,0 +1,120 @@
###############################################
GAME=qw
DEBUG=0
###############################################
CPP=cpp
CPPFLAGS=-I.
QFCC=qfcc
QFCCFLAGS=-q --warn all --code v6only $(CPPFLAGS)
###############################################
QW_SOURCES= $(prefix qw/, \
system.qc builtins.qc sz_watch.qc effect.qc \
)
WEAPONS_SOURCES=weapon.qc weapon_g.qc \
w_void.qc w_axe.qc w_shotgun.qc w_nailgun.qc \
w_grenade_launcher.qc w_rocket_launcher.qc w_lightning_gun.qc
ACT_SOURCES= act.qc act_player.qc act_dead.qc
MDL_SOURCES= mdl.qc mdl_void.qc mdl_player.qc mdl_eyes.qc
MAPENTS_SOURCES=mapents_util.qc \
\
mapents.qc items.qc \
mapents_triggers.qc mapents_movewall.qc mapents_traps.qc \
id_compat.qc mapents_items.qc mapents_powerup.qc
COMMON_SOURCES=system.qc \
\
server.qc worldspawn.qc \
client.qc spectate.qc \
math.qc \
misc.qc \
teleport.qc delays.qc \
bodyque.qc damage.qc \
menu.qc menus.qc \
override.qc \
\
$(prefix weapons/, $(WEAPONS_SOURCES)) \
$(prefix act/, $(ACT_SOURCES)) \
$(prefix mdl/, $(MDL_SOURCES)) \
$(prefix mapents/, $(MAPENTS_SOURCES))
DEBUG_SOURCES= debug.qc entnum.qc
ifeq ($(GAME),qw)
PROGS=../qwprogs.dat
CPPFLAGS+=-DSYSTEM_DIR=\"qw/\"
SOURCES=$(QW_SOURCES) $(COMMON_SOURCES)
else
PROGS=../progs.dat
CPPFLAGS+=-DSYSTEM_DIR=\"nq/\"
SOURCES=$(NQ_SOURCES) $(COMMON_SOURCES)
endif
ifeq ($(DEBUG),1)
CPPFLAGS+=-DDEBUG=1
SOURCES+=$(DEBUG_SOURCES)
endif
OBJECTS=$(SOURCES:.qc=.qfo)
GENERATED_SOURCES = equipid.qh equipid.qc weapon_g.qc
all: $(PROGS)
##########################
$(PROGS): $(OBJECTS)
$(QFCC) $(QFCCFLAGS) -o $@ $^
WEAPON_G_SOURCES=$(filter w_%.qc,$(SOURCES))
weapon_g.qc: weapon_gen.sh $(WEAPON_G_SOURCES)
bash weapon_gen.sh $(WEAPON_G_SOURCES) > $@
EQUIPID_SOURCES=$(filter-out $(GENERATED_SOURCES),$(SOURCES))
equipid.qh equipid.qc: equipid_gen.pl Makefile $(EQUIPID_SOURCES)
cat $(EQUIPID_SOURCES) | perl equipid_gen.pl > equipid.qh
clean:
rm -f $(OBJECTS) $(GENERATED_SOURCES)
#########################
%.qfo: %.qc
$(QFCC) $(QFCCFLAGS) -c $<
#########################
unused:
@echo $(filter-out $(SOURCES),$(wildcard *.qc))
dep: Makefile.deps
Makefile.deps: $(SOURCES)
echo "# Use 'make dep' to generate this file" > $@
for i in $(SOURCES); do \
$(CPP) $(CPPFLAGS) -MM "$$i" | sed -e 's:^.*\::$(PROGS)\::' >> $@; \
done
#########################
.PHONY: unused
#########################
#progs.src: Makefile
# echo $(PROGS) > $@
# for i in $(SOURCES); do echo "$$i" >> $@; done
#
#$(PROGS): progs.src $(SOURCES)
# $(QFCC) $(QFCCFLAGS)
-include Makefile.deps

139
klik/Makefile.deps Normal file
View file

@ -0,0 +1,139 @@
# Use 'make dep' to generate this file
../qwprogs.dat: system.qc
../qwprogs.dat: server.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
server.qh damage.qh bodyque.qh weapon.qh weapon_g.qh mdl.qh client.qh \
mdl_player.qh mdl_eyes.qh act_player.qh delays.qh
../qwprogs.dat: worldspawn.qc common.qh system.qh system.qc \
builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh \
config.qh
../qwprogs.dat: client.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
override.qh mdl.qh mdl_player.qh mdl_void.qh act_player.qh \
act_dead.qh equip.qh equipid.qh items.qh menu.qh menus.qh weapon.qh \
weapon_g.qh server.qh damage.qh teleport.qh
../qwprogs.dat: spectate.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh
../qwprogs.dat: refcount.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh
../qwprogs.dat: sz_watch.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
server.qh protocol.qh
../qwprogs.dat: math.qc math.qh
../qwprogs.dat: entnum.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
server.qh entnum.qh
../qwprogs.dat: misc.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
protocol.qh teleport.qh
../qwprogs.dat: effect.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
protocol.qh effect.qh
../qwprogs.dat: teleport.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
mapents_util.qh damage.qh effect.qh teleport.qh
../qwprogs.dat: delays.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
server.qh delays.qh
../qwprogs.dat: bodyque.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
damage.qh effect.qh mdl.qh bodyque.qh
../qwprogs.dat: damage.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
damage.qh
../qwprogs.dat: equip.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
equip.qh equipid.qh math.qh
../qwprogs.dat: equipid.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
equip.qh equipid.qh
../qwprogs.dat: weapon.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
weapon.qh weapon_g.qh mdl.qh
../qwprogs.dat: weapon_g.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
weapon.qh weapon_g.qh mdl.qh
../qwprogs.dat: w_void.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
weapon.qh weapon_g.qh mdl.qh
../qwprogs.dat: w_axe.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
weapon.qh weapon_g.qh mdl.qh damage.qh effect.qh
../qwprogs.dat: w_shotgun.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
weapon.qh weapon_g.qh mdl.qh equip.qh equipid.qh damage.qh effect.qh
../qwprogs.dat: w_nailgun.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
weapon.qh weapon_g.qh mdl.qh equip.qh equipid.qh damage.qh
../qwprogs.dat: w_grenade_launcher.qc common.qh system.qh \
system.qc builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh \
defs.qh config.qh weapon.qh weapon_g.qh mdl.qh equip.qh equipid.qh \
damage.qh effect.qh
../qwprogs.dat: w_rocket_launcher.qc common.qh system.qh \
system.qc builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh \
defs.qh config.qh weapon.qh weapon_g.qh mdl.qh equip.qh equipid.qh \
damage.qh effect.qh
../qwprogs.dat: w_lightning_gun.qc common.qh system.qh system.qc \
builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh \
config.qh weapon.qh weapon_g.qh mdl.qh equip.qh equipid.qh damage.qh \
effect.qh
../qwprogs.dat: act.qc common.qh system.qh system.qc builtins.qh builtins.qc \
refcount.qh sz_watch.qh misc.qh defs.qh config.qh act.qh items.qh \
damage.qh server.qh
../qwprogs.dat: act_player.qc common.qh system.qh system.qc \
builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh \
config.qh damage.qh mdl.qh client.qh items.qh weapon.qh weapon_g.qh \
equip.qh equipid.qh act.qh act_player.qh override.qh
../qwprogs.dat: act_dead.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
client.qh weapon.qh weapon_g.qh mdl.qh damage.qh act.qh items.qh \
act_dead.qh override.qh
../qwprogs.dat: mdl.qc common.qh system.qh system.qc builtins.qh builtins.qc \
refcount.qh sz_watch.qh misc.qh defs.qh config.qh bodyque.qh mdl.qh
../qwprogs.dat: mdl_void.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh mdl.qh \
mdl_void.qh
../qwprogs.dat: mdl_player.qc common.qh system.qh system.qc \
builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh \
config.qh mdl.qh mdl_player.qh
../qwprogs.dat: mdl_eyes.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh mdl.qh \
mdl_eyes.qh
../qwprogs.dat: menu.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh menu.qh \
menus.qh
../qwprogs.dat: menus.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh menu.qh \
menus.qh
../qwprogs.dat: override.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
items.qh damage.qh teleport.qh override.qh
../qwprogs.dat: mapents_util.qc common.qh system.qh system.qc \
builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh \
config.qh mapents_util.qh
../qwprogs.dat: mapents.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
mapents_util.qh damage.qh
../qwprogs.dat: items.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
mapents_util.qh items.qh
../qwprogs.dat: mapents_triggers.qc common.qh system.qh \
system.qc builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh \
defs.qh config.qh mapents_util.qh damage.qh mapents_triggers.qh
../qwprogs.dat: mapents_movewall.qc common.qh system.qh \
system.qc builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh \
defs.qh config.qh mapents_util.qh damage.qh mapents_movewall.qh
../qwprogs.dat: mapents_traps.qc common.qh system.qh system.qc \
builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh \
config.qh mapents_util.qh damage.qh effect.qh
../qwprogs.dat: id_compat.qc common.qh system.qh system.qc builtins.qh \
builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh config.qh \
mapents_util.qh items.qh mapents_triggers.qh mapents_items.qh \
mapents_movewall.qh equip.qh equipid.qh
../qwprogs.dat: mapents_items.qc common.qh system.qh system.qc \
builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh \
config.qh mapents_util.qh items.qh mapents_items.qh
../qwprogs.dat: mapents_powerup.qc common.qh system.qh system.qc \
builtins.qh builtins.qc refcount.qh sz_watch.qh misc.qh defs.qh \
config.qh mapents_util.qh items.qh override.qh damage.qh equip.qh \
equipid.qh mapents_powerup.qh math.qh

13
klik/TODO Normal file
View file

@ -0,0 +1,13 @@
Make sure everything that's not living gets DEAD_NONLIVING
Clean up util_* and friends.
Go through and re-write all the QUAKED tags
#define SPAWNFUNC to nothing, and prefix all spawn functions with it.
Browse FIXME's :)
Teleporting missiles (i.e., real entities) is a little hackish
to get them teleporting every time.. find a better way..

52
klik/act/act.qc Normal file
View file

@ -0,0 +1,52 @@
#include "common.qh"
#include "act.qh"
#include "server.qh"
void() PlayerPreThink = {
if (is_cl(self))
PlayerStartFrame();
if (self.prethink)
self.prethink();
};
void() act_think = {
if (!is_autothink(self)) {
frametime = 0.1;
PlayerPreThink();
}
/*if (0.1 seconds have passed) {*/
if (self.actthink)
self.actthink();
if (self.menu_think)
self.menu_think();
if (self.mdl_think && !self.mdl_thought)
self.mdl_think();
self.mdl_thought = FALSE;
if (self.w_think && !self.w_thought)
self.w_think();
self.w_thought = FALSE;
/*}*/
self.nextthink = time + 0.1; /* FIXME: Use sv_mintic here when non-client? */
if (!is_autothink(self))
PlayerPostThink();
};
void() PlayerPostThink = {
if (self.postthink)
self.postthink();
if (is_cl(self))
PlayerEndFrame();
};
void() act_setup = {
self.think = act_think;
self.nextthink = time;
};

17
klik/act/act.qh Normal file
View file

@ -0,0 +1,17 @@
#ifndef ACT_qh
#define ACT_qh 1
#include "items.qh"
#include "damage.qh"
@extern {
.void() prethink;
.void() actthink;
.void() postthink;
void() act_setup;
}
#endif

115
klik/act/act_dead.qc Normal file
View file

@ -0,0 +1,115 @@
#include "common.qh"
#include "client.qh"
#include "weapon.qh"
#include "damage.qh"
#include "act.qh"
#include "act_dead.qh"
#include "override.qh"
#define STOP_EPSILON 0.1
void() dead_prethink = {
if (vlen(self.movedir) > vlen(self.velocity)) {
self.velocity = '0 0 0';
} else {
/* FIXME: Use e, decay per frame. */
if (time >= self.pain_finished) {
self.velocity *= 0.9;
self.pain_finished = time + 0.1;
}
if (self.velocity_x > -STOP_EPSILON && self.velocity_x < STOP_EPSILON)
self.velocity_x = 0;
if (self.velocity_y > -STOP_EPSILON && self.velocity_y < STOP_EPSILON)
self.velocity_y = 0;
if (self.velocity_z > -STOP_EPSILON && self.velocity_z < STOP_EPSILON)
self.velocity_z = 0;
}
if (time >= self.air_finished) {
if (self.button0 || self.button2 || self.impulse) {
self.button0 = self.button1 = self.button2 = 0;
self.impulse = 0;
PutClientInGame();
return;
}
}
self.movedir = self.velocity;
};
void() dead_postthink = {
local vector vieworg;
self.dmg_take = 0;
self.dmg_save = 0;
vieworg = vieworigin(self);
if (pointcontents(vieworg + self.velocity*sv_maxtic) != pointcontents(vieworg)) {
self.movetype = MOVETYPE_NONE;
self.velocity = '0 0 0';
setorigin(self, self.origin);
}
};
float() dead_takeitem = { return FALSE; };
float(float d) dead_takedamage = { return FALSE; };
void() act_setup_dead = {
act_setup();
weapon_select_by_impulse(0);
self.solid = SOLID_NOT;
self.takedamage = DAMAGE_NO;
self.movetype = MOVETYPE_NOCLIP;
self.deadflag = DEAD_NONLIVING;
self.impulse = 0;
self.button0 = self.button1 = self.button2 = 0;
self.flags &= ~FL_JUMPRELEASED;
/* Dead people don't have stuff. */
self.items = 0;
self.effects = 0;
self.ammo_shells = 0;
self.ammo_nails = 0;
self.ammo_rockets = 0;
self.ammo_cells = 0;
self.currentammo = 0;
self.itemfield_1 = 0;
self.itemfield_2 = 0;
self.itemfield_3 = 0;
self.itemfield_4 = 0;
/* May need to change these if clients don't act the same. */
self.armorvalue = 0;
self.health = 0.001; // Avoid stupid death roll.
self.gravity = 0;
self.maxspeed = 0;
self.mass = 0;
self.movedir = self.velocity;
self.movedir_z -= sv_gravity * sv_maxtic; /* Gravity hack. */
self.pain_finished = time + 0.1;
self.air_finished = time + 2;
override_set_th_takeitem(self, dead_takeitem);
override_set_th_takedamage(self, dead_takedamage);
override_set_prethink(self, dead_prethink);
override_set_actthink(self, NOTHING_function);
override_set_postthink(self, dead_postthink);
dead_postthink(); /* make sure we don't noclip when near walls */
};

10
klik/act/act_dead.qh Normal file
View file

@ -0,0 +1,10 @@
#ifndef ACT_DEAD_qh
#define ACT_DEAD_qh 1
@extern {
void() act_setup_dead;
};
#endif

671
klik/act/act_player.qc Normal file
View file

@ -0,0 +1,671 @@
#include "common.qh"
#include "damage.qh"
#include "mdl.qh"
#include "client.qh"
#include "misc.qh"
#include "items.qh"
#include "weapon.qh"
#include "equip.qh"
#include "act.qh"
#include "act_player.qh"
#include "override.qh"
void() act_player_init = {
precache_sound("player/plyrjmp8.wav");
precache_sound("player/h2ojump.wav");
precache_sound("player/land.wav");
precache_sound("player/land2.wav");
precache_sound("player/inh2o.wav");
precache_sound("player/slimbrn2.wav");
precache_sound("player/inlava.wav");
precache_sound("misc/water1.wav");
precache_sound("misc/water2.wav");
precache_sound("player/drown1.wav");
precache_sound("player/drown2.wav");
precache_sound("player/lburn1.wav");
precache_sound("player/lburn2.wav");
precache_sound("player/gasp1.wav");
precache_sound("player/gasp2.wav");
precache_sound("misc/outwater.wav");
precache_sound("player/pain1.wav");
precache_sound("player/pain2.wav");
precache_sound("player/pain3.wav");
precache_sound("player/pain4.wav");
precache_sound("player/pain5.wav");
precache_sound("player/pain6.wav");
precache_sound("player/death1.wav");
precache_sound("player/death2.wav");
precache_sound("player/death3.wav");
precache_sound("player/death4.wav");
precache_sound("player/death5.wav");
precache_sound("player/gib.wav");
precache_sound("player/udeath.wav");
precache_sound("player/h2odeath.wav");
precache_model("progs/backpack.mdl");
precache_sound("weapons/lock4.wav");
precache_sound("items/itembk2.wav");
};
// ========================================================================
void(float scl) player_throw_ammo = {
local entity player;
player = self;
self = spawn("BACKPACK");
if (scl > 1) {
/* FIXME: This is actually a hack to avoid powerups */
#define qg(eid) \
if (equip_query(player, eid)) \
equip_grant(self, eid) \
qg(EQUIPID_SUPER_SHOTGUN);
qg(EQUIPID_NAILGUN);
qg(EQUIPID_SUPER_NAILGUN);
qg(EQUIPID_GRENADE_LAUNCHER);
qg(EQUIPID_ROCKET_LAUNCHER);
qg(EQUIPID_LIGHTNING_GUN);
#undef qg
player.itemfield_1 = 0;
player.itemfield_2 = 0;
player.itemfield_3 = 0;
player.itemfield_4 = 0;
scl = 1;
}
self.ammo_shells = player.ammo_shells * scl;
player.ammo_shells -= self.ammo_shells;
self.ammo_nails = player.ammo_nails * scl;
player.ammo_nails -= self.ammo_nails;
self.ammo_rockets = player.ammo_rockets * scl;
player.ammo_rockets -= self.ammo_rockets;
self.ammo_cells = player.ammo_cells * scl;
player.ammo_cells -= self.ammo_cells;
if (!self.ammo_shells && !self.ammo_nails && !self.ammo_rockets && !self.ammo_cells
&& !self.itemfield_1 && !self.itemfield_2 && !self.itemfield_3 && !self.itemfield_4) {
remove(self);
self = player;
return;
}
self.origin = center(player);
self.movetype = MOVETYPE_TOSS;
self.velocity_x = crandom()*100;
self.velocity_y = crandom()*100;
self.velocity_z = 200;
self.mins = '-16 -16 0';
self.maxs = '16 16 56';
self.model = "progs/backpack.mdl";
self.noise2 = "weapons/lock4.wav";
self.noise7 = "items/itembk2.wav";
self.wait = -1;
self.think = SUB_remove;
self.nextthink = time + 20 + random()*20;
item_generic();
self = player;
};
void() player_die = {
local float r;
if (self.health > CONFIG_GIB_HEALTH) {
if (self.waterlevel >= 3) {
self.noise = "player/h2odeath.wav";
} else {
r = random()*5;
if (r < 1) self.noise = "player/death1.wav";
else if (r < 2) self.noise = "player/death2.wav";
else if (r < 3) self.noise = "player/death3.wav";
else if (r < 4) self.noise = "player/death4.wav";
else self.noise = "player/death5.wav";
}
sound(self, CHAN_VOICE, self.noise, 1, ATTN_NONE);
player_throw_ammo(2);
mdl_bodyque_and_func(MDL_FUNC_DIE, floor(random()*5));
} else {
r = random()*2;
if (r < 1) self.noise = "player/gib.wav";
else self.noise = "player/udeath.wav";
sound(self, CHAN_VOICE, self.noise, 1, ATTN_NONE);
mdl_bodyque_and_func(MDL_FUNC_GIB, 0);
}
makevectors(self.angles); /* Not v_angle! */
self.velocity = (v_forward*-200) + (v_up*100);
if (self.v_angle_x < 75 && self.v_angle_x > -75) {
self.angles = self.v_angle;
self.angles_x += 20;
self.fixangle = TRUE;
}
/* FIXME: Hack. */
setorigin(self, vieworigin(self));
RemoveClientFromGame();
};
// ========================================================================
float(float d) _player_takedamage_core = {
self.health -= d;
self.dmg_take += d;
if (floor(self.health) <= 0) {
deathmsg_display();
player_die();
} else {
deathmsg_nodisplay();
self.mdl_func(MDL_FUNC_PAIN, d);
}
return TRUE;
};
float(float d) player_takedamage = {
local float r, taked;
damage_push(d);
taked = damage_armor(d);
self.dmg_save = self.dmg_save + (d - taked);
if (taked <= 0)
return FALSE;
if (self.pain_finished < time) {
if ((self.mdl_mod & MDL_MOD_SWIM_IN) && self.air_finished < (time + random()*9)) {
r = random()*2;
if (r < 1) self.noise = "player/drown2.wav";
else self.noise = "player/drown1.wav";
} else {
r = random()*5;
if (r < 1) self.noise = "player/pain1.wav";
else if (r < 2) self.noise = "player/pain2.wav";
else if (r < 3) self.noise = "player/pain3.wav";
else if (r < 4) self.noise = "player/pain4.wav";
else if (r < 5) self.noise = "player/pain5.wav";
else self.noise = "player/pain6.wav";
}
sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.pain_finished = time + 1;
}
return _player_takedamage_core(taked);
};
// ========================================================================
float(float d) _player_takedamage_drown = {
local float r;
if (d <= 0)
return FALSE;
if (self.pain_finished < time) {
r = random()*2;
if (r < 1) self.noise = self.noise3;
else self.noise = self.noise4;
sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.pain_finished = time + 1;
}
return _player_takedamage_core(d);
};
float(float d) _player_takedamage_melt = {
local float r, taked;
taked = damage_armor(d);
self.dmg_save += d - taked;
if (taked <= 0)
return FALSE;
if (self.pain_finished < time) {
r = random()*2;
if (r < 1) self.noise = self.noise3;
else self.noise = self.noise4;
sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.pain_finished = time + 1;
}
return _player_takedamage_core(taked);
};
float(float d, float(float d) damg_func, void() deathmessage) _player_damage_custom = {
local float ret;
override_set_th_takedamage(self, damg_func);
ret = damage(self, self, world, d, deathmessage);
override_set_th_takedamage(self, player_takedamage);
return ret;
};
// ========================================================================
void() _deathmsg_player_liquid = {
local string def_nname;
local float r;
def_nname = name(self);
if (self.watertype == CONTENT_WATER) {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " sleeps with the fishes.\n");
else bprint(PRINT_DEATH, def_nname, " hunts for air.\n");
} else if (self.watertype == CONTENT_SLIME) {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " can't exist on slime alone.\n");
else bprint(PRINT_DEATH, def_nname, " floats in slime.\n");
} else if (self.watertype == CONTENT_LAVA) {
r = random()*3;
if (r < 1) bprint(PRINT_DEATH, def_nname, " swam in a volcano.\n");
else if (r < 2) bprint(PRINT_DEATH, def_nname, " turned into hot slag.\n");
else bprint(PRINT_DEATH, def_nname, " parties with Chthon.\n");
} else {
bprint(PRINT_DEATH, def_nname, " gulps it down.\n");
}
};
void() _deathmsg_player_fall = {
local string def_name;
local float r;
def_name = name(self);
r = random()*3;
if (r < 1) bprint(PRINT_DEATH, def_name, " landed head-first.\n");
else if (r < 2) bprint(PRINT_DEATH, def_name, " cratered.\n");
else bprint(PRINT_DEATH, def_name, " took a nose dive into the ground.\n");
};
// ========================================================================
/* This is so stupid. */
float() _player_jump = {
if (!self.button2) {
self.flags |= FL_JUMPRELEASED;
return FALSE;
}
if (!(self.flags & FL_ONGROUND))
return FALSE;
if (!(self.flags & FL_JUMPRELEASED))
return FALSE;
self.mdl_func(MDL_FUNC_JUMP, 0);
self.flags &= ~FL_JUMPRELEASED;
self.button2 = 0;
return TRUE;
};
void() _player_water_jump = {
if (self.waterlevel <= 1) {
if (_player_jump())
sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
return;
}
if (self.waterlevel <= 2) {
if (_player_jump())
sound(self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM);
}
/* Yeah. The engine is a piece of crap. */
if (self.button2) {
if (self.flags & FL_ONGROUND) {
self.flags = self.flags - FL_ONGROUND;
self.origin_z = self.origin_z + 1;
}
}
};
/* This is called every frame... */
void() player_prethink = {
/* Gasp for air if we weren't swimming..
/* Checking here rather than later, with mdl_mod is a HACK */
/* It avoids the gasp when the player hasn't communicated
with the server in a while (it happens..) */
if (self.waterlevel < 3) {
if (self.mdl_mod&MDL_MOD_SWIM_IN) {
if (self.air_finished < time)
sound(self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
else if (self.air_finished < (time + 9))
sound(self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
}
self.air_finished = time + 12;
}
/* Let the MDL (and us) know we're swimming */
self.mdl_mod &= ~MDL_MOD_SWIM;
if (self.waterlevel >= 3)
self.mdl_mod |= MDL_MOD_SWIM_IN;
else if (self.waterlevel >= 1)
self.mdl_mod |= MDL_MOD_SWIM_OVER;
/* Handle environmental damage */
if (self.watertype == CONTENT_SLIME) {
self.noise3 = "player/lburn1.wav";
self.noise4 = "player/lburn2.wav";
_player_damage_custom(4*self.waterlevel*frametime, _player_takedamage_melt, _deathmsg_player_liquid);
} else if (self.watertype == CONTENT_LAVA) {
self.noise3 = "player/lburn1.wav";
self.noise4 = "player/lburn2.wav";
_player_damage_custom(50*self.waterlevel*frametime, _player_takedamage_melt, _deathmsg_player_liquid);
}
/* Try to breathe :) */
if (self.air_finished < time) {
local float damg;
damg = (time - self.air_finished) * 0.2;
if (damg > 1.5) damg = 1.5;
self.noise3 = "player/drown1.wav";
self.noise4 = "player/drown2.wav";
_player_damage_custom(damg, _player_takedamage_drown, _deathmsg_player_liquid);
}
/* Enter/exit water, swim sound */
if (!self.waterlevel) {
if (self.flags & FL_INWATER) {
sound(self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
self.flags = self.flags - FL_INWATER;
}
if (_player_jump())
sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
} else {
if (!(self.flags & FL_INWATER)) {
if (self.watertype == CONTENT_WATER)
self.noise = "player/inh2o.wav";
else if (self.watertype == CONTENT_SLIME)
self.noise = "player/slimbrn2.wav";
else if (self.watertype == CONTENT_LAVA)
self.noise = "player/inlava.wav";
sound(self, CHAN_BODY, self.noise, 1, ATTN_NORM);
self.flags = (self.flags & ~FL_JUMPRELEASED) | FL_INWATER;
self.water_finished = 0;
}
if (self.mdl_mod&MDL_MOD_SWIM) {
local float increment, mxspeed;
increment = vlen(self.origin - self.pos1);
mxspeed = calc_max_speed(self);
if (increment > mxspeed)
increment = mxspeed;
self.water_finished += increment;
if (self.water_finished >= mxspeed) {
self.water_finished = 0;
if (random() < 0.5) self.noise = "misc/water1.wav";
else self.noise = "misc/water2.wav";
sound(self, CHAN_BODY, self.noise, 1, ATTN_NORM);
}
}
_player_water_jump();
}
self.pos1 = self.origin;
#if DEBUG
debug_impulse();
#endif
weapon_player_impulse();
};
/* This is not called every frame */
void() player_think = {
/* The player does not think. */
};
/* FIXME: We should check to see if we actually collided.
I don't know how to at the moment... */
void() player_velocity_damage = {
local vector vel, dir;
local float v1, v2;
vel = self.movedir;
self.movedir = self.velocity;
/* Did we just teleport? */
if (self.teleport_time)
return;
/* Did we slow down a lot? */
v1 = vlen(vel);
v2 = vlen(self.velocity);
if (v2 >= v1)
return;
vel = vel - self.velocity;
vel_z = vel_z * 2;
v1 = vlen(vel);
/* Find the largest magnitude dir */
vel_x = fabs(vel_x);
vel_y = fabs(vel_y);
vel_z = fabs(vel_z);
dir = '0 0 1';
if (vel_y > (vel*dir))
dir = '0 1 0';
if (vel_x > (vel*dir))
dir = '1 0 0';
/* Play sounds, apply damage */
if (v1 > CONFIG_LAND_SOUND) {
if (dir_z && self.watertype == CONTENT_WATER) {
self.noise = "player/h2ojump.wav";
} else if (v1 > CONFIG_LAND_HURT) {
self.noise = "player/land2.wav";
self.pain_finished = time + 1;
damage(self, self, world, 5, _deathmsg_player_fall);
} else {
self.noise = "player/land.wav";
}
sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
}
};
/* This is also called every frame... */
void() player_postthink = {
player_velocity_damage();
self.items &= ~(IT_ARMOR1|IT_ARMOR2|IT_ARMOR3);
if (self.armortype >= 0.8)
self.items |= IT_ARMOR3;
else if (self.armortype >= 0.6)
self.items |= IT_ARMOR2;
else if (self.armortype >= 0.3)
self.items |= IT_ARMOR1;
update_weapon_flags();
weapon_set_ammo();
};
// ========================================================================
void(float nitem, string str1, string str2) _item_xprint_strs = {
if (!is_cl(self))
return;
if (!str1) return;
if (nitem == 1) {
stuffcmd(self, "bf\n");
xprint_start(self, PRINT_LOW);
xprint_str("You get ");
} else if (nitem > 1) xprint_str(", ");
xprint_str(str1);
if (str2) xprint_str(str2);
};
void(float nitem, string str1, string str2) _item_xprint_strs_last = {
if (!is_cl(self))
return;
if (!str1) return;
if (nitem == 1) {
stuffcmd(self, "bf\n");
xprint_start(self, PRINT_LOW);
xprint_str("You get ");
}
if (nitem == 2) xprint_str(" and ");
else if (nitem > 2) xprint_str(", and ");
xprint_str(str1);
if (str2) xprint_str(str2);
xprint_str("\n");
};
float nitem;
string str1, str2;
void(.float fld, float max, string sing, string plur) _player_takefield = {
local float new, diff;
new = increase_bound(self.fld, other.fld, max);
if (new > 999) new = 999;
if (new > self.fld) {
diff = floor(new) - floor(self.fld);
if (!diff) diff = new - self.fld;
_item_xprint_strs(nitem, str1, str2);
str1 = ftos(diff);
if (diff == 1) str2 = sing;
else str2 = plur;
nitem++;
self.fld = new;
}
};
float() player_takeitem = {
local float eid;
nitem = 0;
str1 = NULL_string;
str2 = NULL_string;
while ((eid = equip_iter(other)) != -1) {
if (equip_query(self, eid))
continue;
equip_grant(self, eid);
_item_xprint_strs(nitem, str1, str2);
str1 = "the ";
str2 = equip_id_to_string(eid);
nitem++;
}
_player_takefield(ammo_shells, self.max_ammo_shells, " shell", " shells");
_player_takefield(ammo_nails, self.max_ammo_nails, " nail", " nails");
_player_takefield(ammo_rockets, self.max_ammo_rockets, " rocket", " rockets");
_player_takefield(ammo_cells, self.max_ammo_cells, " cell", " cells");
if (other.armorvalue <= self.max_armor) {
if ((other.armorvalue*other.armortype) > (self.armorvalue*self.armortype)) {
self.armorvalue = other.armorvalue;
self.armortype = other.armortype;
_item_xprint_strs(nitem, str1, str2);
str2 = NULL_string;
if (self.armortype >= 0.8)
str1 = "strong armor";
else if (self.armortype >= 0.6)
str1 = "medium armor";
else if (self.armortype >= 0.3)
str1 = "light armor";
else
str1 = "really crappy armor";
nitem++;
}
}
_player_takefield(health, self.max_health, " health", " health");
_item_xprint_strs_last(nitem, str1, str2);
if (nitem) return TRUE;
return FALSE;
};
// ===================================================================== //
void() act_setup_player = {
act_setup();
self.movedir = '0 0 0';
self.solid = SOLID_SLIDEBOX;
self.takedamage = DAMAGE_AIM;
self.movetype = MOVETYPE_WALK;
self.deadflag = DEAD_NO;
self.gravity = 1;
self.maxspeed = sv_maxspeed;
self.mass = 1000;
self.air_finished = time + 12;
self.pain_finished = 0;
self.water_finished = 0;
override_set_th_takeitem(self, player_takeitem);
override_set_th_takedamage(self, player_takedamage);
override_set_prethink(self, player_prethink);
override_set_actthink(self, player_think);
override_set_postthink(self, player_postthink);
};

11
klik/act/act_player.qh Normal file
View file

@ -0,0 +1,11 @@
#ifndef ACT_PLAYER_qh
#define ACT_PLAYER_qh 1
@extern {
void() act_player_init;
void() act_setup_player;
};
#endif

135
klik/bodyque.qc Normal file
View file

@ -0,0 +1,135 @@
#include "common.qh"
#include "damage.qh"
#include "effect.qh"
#include "mdl.qh"
#include "bodyque.qh"
float _bodyque_current;
entity bodyque_head;
void() bodyque_init = {
local float i;
local entity e;
e = bodyque_head = spawn("BODYQUE");
bodyque_head.owner = bodyque_head;
for (i = 1; i < CONFIG_BODYQUE_MAX; i = i + 1) {
bodyque_head.owner = spawn("BODYQUE");
bodyque_head.owner.chain = bodyque_head;
bodyque_head = bodyque_head.owner;
}
e.chain = bodyque_head;
bodyque_head.owner = e;
precache_sound("zombie/z_miss.wav");
precache_sound("player/gib.wav");
precache_sound("player/udeath.wav");
};
void() _bodyque_fade_think = {
local vector org;
if (self.mdl_think) {
if (!self.mdl_thought) self.mdl_think();
self.mdl_thought = FALSE;
}
org = self.origin;
org_z = org_z + self.maxs_z;
if (pointcontents(org) == CONTENT_SOLID) {
_bodyque_current = _bodyque_current - 1;
remove(self);
return;
}
self.nextthink = time + 0.1;
};
void() _bodyque_fade_from_reality = {
local entity new_bodyque;
if (_bodyque_current >= CONFIG_BODYQUE_FADE_MAX)
return;
new_bodyque = spawn("BODYQUE");
// Link the new entity in, let the old one fade
if (bodyque_head.owner != bodyque_head) {
new_bodyque.owner = bodyque_head.owner;
new_bodyque.chain = bodyque_head.chain;
new_bodyque.owner.chain = new_bodyque;
new_bodyque.chain.owner = new_bodyque;
} else {
// This happens if CONFIG_BODYQUE_MAX == 1
new_bodyque.owner = new_bodyque;
new_bodyque.chain = new_bodyque;
}
bodyque_head.movetype = MOVETYPE_NOCLIP;
bodyque_head.think = _bodyque_fade_think;
bodyque_head.nextthink = time + 0.1;
bodyque_head.velocity = '0 0 -10';
bodyque_head = new_bodyque;
_bodyque_current = _bodyque_current + 1;
};
void() _bodyque_think = {
if (self.mdl_think) {
if (!self.mdl_thought) self.mdl_think();
self.mdl_thought = FALSE;
}
self.nextthink = time + 0.1;
};
entity(entity body) bodyque_que = {
local entity ret;
if (bodyque_head.count)
_bodyque_fade_from_reality();
ret = bodyque_head;
bodyque_head.deadflag = DEAD_DEAD;
bodyque_head.count = TRUE;
bodyque_head.model = body.model;
bodyque_head.modelindex = body.modelindex;
bodyque_head.mins = body.mins;
bodyque_head.maxs = body.maxs;
bodyque_head.size = body.size;
bodyque_head.angles = body.angles;
bodyque_head.frame = body.frame;
bodyque_head.colormap = body.colormap;
bodyque_head.movetype = body.movetype;
bodyque_head.velocity = body.velocity;
bodyque_head.avelocity = body.avelocity;
bodyque_head.health = body.health;
bodyque_head.mass = body.mass;
bodyque_head.solid = SOLID_NOT;
bodyque_head.movetype = MOVETYPE_BOUNCE;
bodyque_head.takedamage = DAMAGE_NO;
bodyque_head.mdl_func = body.mdl_func;
bodyque_head.mdl_mod = body.mdl_mod;
bodyque_head.mdl_think = body.mdl_think;
bodyque_head.mdl_thought = body.mdl_thought;
setorigin(bodyque_head, body.origin);
setsize(bodyque_head, body.mins, body.maxs);
bodyque_head.think = _bodyque_think;
bodyque_head.nextthink = time + 0.1;
bodyque_head = bodyque_head.owner;
return ret;
};

11
klik/bodyque.qh Normal file
View file

@ -0,0 +1,11 @@
#ifndef BODYQUE_qh
#define BODYQUE_qh 1
@extern {
void() bodyque_init;
entity(entity body) bodyque_que;
};
#endif

6
klik/builtins.qh Normal file
View file

@ -0,0 +1,6 @@
#ifndef BUILTINS_qh
#define BUILTINS_qh 1
#include SYSTEM_DIR "builtins.qh"
#endif

230
klik/client.qc Normal file
View file

@ -0,0 +1,230 @@
#include "common.qh"
#include "misc.qh"
#include "override.qh"
#include "mdl.qh"
#include "mdl_player.qh"
#include "mdl_void.qh"
#include "act_player.qh"
#include "act_dead.qh"
#include "equip.qh"
#include "items.qh"
#include "menu.qh"
#include "weapon.qh"
#include "server.qh"
#include "damage.qh"
#include "teleport.qh"
void() client_init = {
precache_model("progs/player.mdl");
precache_model("progs/eyes.mdl");
};
// This is the first function called by C code for a new player.
void() SetNewParms = {
parm1 = CONFIG_START_CURRENCY;
parm2 = parm3 = parm4 = parm5 = 0;
parm6 = CONFIG_START_HEALTH + CONFIG_START_ARMOR*999;
parm7 = CONFIG_START_ARMOR_TYPE;
parm8 = CONFIG_MAX_HEALTH + CONFIG_MAX_ARMOR*999;
parm9 = CONFIG_START_SHELLS + CONFIG_START_NAILS*999;
parm10 = CONFIG_START_ROCKETS + CONFIG_START_CELLS*999;
parm11 = CONFIG_MAX_SHELLS + CONFIG_MAX_NAILS*999;
parm12 = CONFIG_MAX_ROCKETS + CONFIG_MAX_CELLS*999;
parm15 = weapon_player_parm1_default();
parm16 = EQUIP_STATE_CHOOSE;
};
void() SetDeadParms = {
SetNewParms();
};
// Called when about to change maps
void() SetChangeParms = {
/* Currency */
parm1 = self.currency;
/* Purchased items */
parm2 = self.itemfield_1;
parm3 = self.itemfield_2;
parm4 = self.itemfield_3;
parm5 = self.itemfield_4;
/* Health and such */
if (self.health < 0) self.health = 0;
parm6 = self.health + self.armorvalue*999;
parm7 = self.armortype;
parm8 = self.max_health + self.max_armor*999;
/* Ammo */
parm9 = self.ammo_shells + self.ammo_nails*999;
parm10 = self.ammo_rockets + self.ammo_cells*999;
parm11 = self.max_ammo_shells + self.max_ammo_nails*999;
parm12 = self.max_ammo_rockets + self.max_ammo_cells*999;
/* Wheeee */
parm15 = weapon_player_parm1();
parm16 = self.equip_state;
/* H4x0r */
if (self.deadflag)
SetDeadParms();
};
void() DecodeParms = {
/* Currency */
self.currency = parm1;
/* Purchased items */
self.itemfield_1 = parm2;
self.itemfield_2 = parm3;
self.itemfield_3 = parm4;
self.itemfield_4 = parm5;
equip_grant(self, EQUIPID_SHOTGUN);
/* Health and such */
self.armorvalue = floor(parm6 / 999);
self.armortype = parm7;
self.health = parm6 - self.armorvalue*999;
self.max_armor = floor(parm8 / 999);
self.max_health = parm8 - self.max_armor*999;
/* Ammo */
self.ammo_nails = floor(parm9 / 999);
self.ammo_shells = parm9 - self.ammo_nails*999;
self.ammo_rockets = floor(parm10 / 999);
self.ammo_cells = parm10 - self.ammo_rockets*999;
self.max_ammo_nails = floor(parm11 / 999);
self.max_ammo_shells = parm11 - self.max_ammo_nails*999;
self.max_ammo_rockets = floor(parm12 / 999);
self.max_ammo_cells = parm12 - self.max_ammo_rockets*999;
/* Wheeee */
weapon_player_parm1_decode(parm15);
self.equip_state = parm16;
SetDeadParms();
};
void() RemoveClientFromGame = {
self.classname = "player_outofgame";
mdl_setup_void();
act_setup_dead();
};
void() PutClientInGame = {
local entity ent;
local float spawncount;
menu_set(NOTHING_function);
self.classname = "player";
DecodeParms();
mdl_setup_player();
act_setup_player();
self.velocity = '0 0 0';
self.flags &= ~FL_INWATER;
/* FIXME: Hack to avoid jumping on spawn.... */
self.velocity_z = -270;
/* Select a spawn point.. */
for (spawncount = 5; spawncount > 0; spawncount--) {
spawn_head = random_enemy_chain(spawn_head);
ent = findradius(spawn_head.origin, 100);
while (ent) {
if (ent.classname == "player")
break;
ent = ent.chain;
}
if (!ent)
break;
}
teleport(self, spawn_head);
};
// Called right after ClientConnect, and on new maps.
void() PutClientInServer = {
local entity spot;
/* Hack to get pmodel for servers that check it */
self.model = "progs/player.mdl";
self.modelindex = 0;
intermission_head = spot = random_enemy_chain(intermission_head);
self.origin = spot.origin;
self.angles = spot.angles;
self.fixangle = TRUE;
self.velocity = '0 0 0';
weapon_player_init();
menu_set(menu_intro);
RemoveClientFromGame();
};
void() _deathmsg_suicide = {
local float r;
local string nname;
nname = name(self);
r = random();
if (r < 0.25) bprint(PRINT_DEATH, nname, " says good bye to this cruel world.\n");
else if (r < 0.5) bprint(PRINT_DEATH, nname, " takes the easy way out.\n");
else if (r < 0.75) bprint(PRINT_DEATH, nname, " suicides.\n");
else bprint(PRINT_DEATH, nname, " stands at the wrong end of his shotgun.\n");
};
// C Code calls this when the player issues a 'kill' command.
void()
ClientKill = {
damage(self, self, self, DAMAGE_MUSTDIE, _deathmsg_suicide);
};
void() _client_th_kill = {
if (other == self) self.frags--;
else self.frags++;
logfrag(self, other);
};
// Called after the client is fully connected
void() ClientConnect = {
bprint(PRINT_HIGH, name(self), " connected\n");
self.flags |= FL_CLIENT;
override_set_th_kill(self, _client_th_kill);
};
// Called when the client disconnects
void() ClientDisconnect = {
self.flags = 0;
bprint(PRINT_HIGH, name(self), " disconnected with ", ftos(self.frags), " frags\n");
override_set_th_kill(self, NOTHING_function);
self.deathmsg1 = NULL_string;
damage(self, self, self, DAMAGE_MUSTDIE, NOTHING_function);
};

16
klik/client.qh Normal file
View file

@ -0,0 +1,16 @@
#ifndef CLIENT_qh
#define CLIENT_qh 1
@extern {
void() client_init;
void() RemoveClientFromGame;
void() PutClientInGame;
void() ClientConnect;
void() ClientDisconnect;
};
#endif

10
klik/common.qh Normal file
View file

@ -0,0 +1,10 @@
#include "system.qh"
#include "builtins.qh"
#include "defs.qh"
#include "config.qh"
#if DEBUG
#include "debug.qh"
#endif

37
klik/config.qh Normal file
View file

@ -0,0 +1,37 @@
#ifndef CONFIG_qh
#define CONFIG_qh 1
// ========== User configurable stuff ============
#define CONFIG_STATS_DELAY 0.2
#define CONFIG_START_CURRENCY 15000
#define CONFIG_START_HEALTH 100
#define CONFIG_MAX_HEALTH 100
#define CONFIG_START_ARMOR 0
#define CONFIG_START_ARMOR_TYPE 0
#define CONFIG_MAX_ARMOR 200
#define CONFIG_START_SHELLS 15
#define CONFIG_MAX_SHELLS 100
#define CONFIG_START_NAILS 0
#define CONFIG_MAX_NAILS 200
#define CONFIG_START_ROCKETS 0
#define CONFIG_MAX_ROCKETS 100
#define CONFIG_START_CELLS 0
#define CONFIG_MAX_CELLS 100
#define CONFIG_GIB_HEALTH -40
#define CONFIG_LAND_SOUND 600
#define CONFIG_LAND_HURT 1300
#define CONFIG_BODYQUE_MAX 3
#define CONFIG_BODYQUE_FADE_MAX 7
#endif

218
klik/damage.qc Normal file
View file

@ -0,0 +1,218 @@
#include "common.qh"
#include "misc.qh"
#include "damage.qh"
void() damage_init = {
ghost_inflictor = spawn("GHOST_INFLICTOR");
};
void(entity from, entity to) deathmsg_copy = {
to.deathmsg1 = from.deathmsg1;
to.deathmsg2 = from.deathmsg2;
to.deathmsg3 = from.deathmsg3;
to.deathmsg4 = from.deathmsg4;
to.deathmsg5 = from.deathmsg5;
to.deathmsg6 = from.deathmsg6;
};
string(entity e, string s) _deathmsg_custom_str = {
if (s == "name(self)") return name(self);
if (s == "name(attacker)") return name(self.dmg_attacker);
if (s == "name(inflictor)") return name(self.dmg_inflictor);
return s;
};
void() _deathmsg_custom = {
local string s1, s2, s3, s4, s5, s6;
s1 = s2 = s3 = s4 = s5 = s6 = "";
s1 = _deathmsg_custom_str(self, self.deathmsg1);
if (s1) s2 = _deathmsg_custom_str(self, self.deathmsg2);
if (s2) s3 = _deathmsg_custom_str(self, self.deathmsg3);
if (s3) s4 = _deathmsg_custom_str(self, self.deathmsg4);
if (s4) s5 = _deathmsg_custom_str(self, self.deathmsg5);
if (s5) s6 = _deathmsg_custom_str(self, self.deathmsg6);
// I don't use separate bprints, because iD in all its wisdom
// made them unreliable -- I'd rather lose the whole thing than parts.
bprint(PRINT_DEATH, s1, s2, s3, s4, s5, s6);
};
void() deathmsg_nodisplay = {
refcount_dec(self.dmg_attacker);
refcount_dec(self.dmg_inflictor);
self.dmg_attacker = world;
self.dmg_inflictor = world;
self.deathmsg = NOTHING_function;
};
void() deathmsg_display = {
if (self.th_die)
self.th_die();
if (other.th_kill) {
local entity oldself, oldother;
oldself = self;
oldother = other;
self = oldother;
other = oldself;
self.th_kill();
self = oldself;
other = oldother;
}
self.deathmsg();
deathmsg_nodisplay();
};
float(float d) damage_armor = {
local float adamg, rest;
adamg = d * self.armortype;
if (self.armorvalue < adamg)
adamg = self.armorvalue;
rest = d - adamg;
self.armorvalue = self.armorvalue - adamg;
if (self.armorvalue <= 0) {
self.armorvalue = 0;
self.armortype = 0.0;
}
return rest;
};
void(float d) damage_push = {
local vector vel;
if (self.mass == 0) {
d = 0;
} else {
if (self.dmg_attacker == self)
d = (self.dmg_inflictor.mass + d*rocket_jump) / self.mass;
else
d = self.dmg_inflictor.mass / self.mass;
}
if (self.dmg_inflictor.velocity == '0 0 0') {
vel = normalize(self.origin - self.dmg_inflictor.origin);
vel *= self.dmg_inflictor.speed;
} else {
vel = self.dmg_inflictor.velocity;
}
self.velocity += d * vel;
};
// deathmessage _IS_ overridden if inflictor.deathmsg1
float(entity ent, entity attacker, entity inflictor, float d, void() deathmessage)
damage = {
local entity oldself, oldother;
local float wasdamaged;
if (!ent.takedamage)
return FALSE;
oldself = self;
oldother = other;
ent.dmg_attacker = attacker;
ent.dmg_inflictor = inflictor;
refcount_inc(ent.dmg_attacker);
refcount_inc(ent.dmg_inflictor);
if (inflictor.deathmsg1)
ent.deathmsg = _deathmsg_custom;
else
ent.deathmsg = deathmessage;
if (attacker.th_dealdamage) {
self = attacker;
other = ent;
d = self.th_dealdamage(d);
self = oldself;
other = oldother;
if (d < 0) return FALSE;
}
self = ent;
other = attacker;
wasdamaged = self.th_takedamage(d);
self = oldself;
other = oldother;
return wasdamaged;
};
float(vector org, entity e) _damage_radius_can_hit = {
if (e.movetype == MOVETYPE_PUSH) {
traceline(org, center(e), TRUE, world);
if (trace_fraction == 1 || trace_ent == e)
return TRUE;
return FALSE;
}
traceline(org, e.origin, TRUE, self);
if (trace_fraction == 1) return TRUE;
traceline(org, e.origin + '15 15 0', TRUE, self);
if (trace_fraction == 1) return TRUE;
traceline(org, e.origin + '15 -15 0', TRUE, self);
if (trace_fraction == 1) return TRUE;
traceline(org, e.origin + '-15 15 0', TRUE, self);
if (trace_fraction == 1) return TRUE;
traceline(org, e.origin + '-15 -15 0', TRUE, self);
if (trace_fraction == 1) return TRUE;
return FALSE;
};
void(entity ignore, entity attacker, entity inflictor, void() deathmessage)
damage_radius = {
local entity head;
local vector iorg, org;
local float points;
local float d, m, r;
d = inflictor.dmg;
m = inflictor.mass;
r = inflictor.lip;
iorg = center(inflictor);
for (head = findradius(iorg, r + 40); head; head = head.chain) {
if (head == ignore)
continue;
if (!_damage_radius_can_hit(iorg, head))
continue;
org = center(head);
points = r - (0.5 * vlen(iorg - org));
if (points <= 0)
continue;
if (head == attacker)
points *= 0.5;
inflictor.dmg = (points * d) / r;
inflictor.mass = (points * m) / r;
damage(head, attacker, inflictor, inflictor.dmg, deathmessage);
}
};

56
klik/damage.qh Normal file
View file

@ -0,0 +1,56 @@
#ifndef DAMAGE_qh
#define DAMAGE_qh 1
@extern {
#define DAMAGE_SHOULDDIE 16777214
#define DAMAGE_MUSTDIE 16777215
.entity dmg_attacker;
.void() deathmsg;
.string deathmsg1, deathmsg2, deathmsg3, deathmsg4, deathmsg5, deathmsg6;
// You _MUST_ have th_takedamage if you .takedamage!
// Return TRUE if you were damaged, FALSE otherwise.
.float(float dmg) th_takedamage;
/* Allows you to globally override damage you deal */
/* self = you, other = target */
/* returns new amount of damage, or < 0 for don't */
.float(float dmg) th_dealdamage;
/* Use this when you attack something. It may modify missile. */
/* You should have at least classname, velocity, dmg, and mass */
#define damage_attack(missile) do{ if (self.th_attack) self.th_attack(missile); }while(0)
.void(entity missile) th_attack;
/* Update frags in these. */
.void() th_die;
.void() th_kill;
/* ghost_inflictor is for radius and bullets...
Only guaranteed to have:
classname
velocity
mass
*/
entity ghost_inflictor;
void() damage_init;
void(entity from, entity to) deathmsg_copy;
void() deathmsg_display;
void() deathmsg_nodisplay;
float(float d) damage_armor;
void(float d) damage_push;
float(entity ent, entity attacker, entity inflictor, float d, void() deathmessage) damage;
/* Fill in appropriate fields, inflictor _WILL_ be modified. */
void(entity ignore, entity attacker, entity inflictor, void() deathmessage) damage_radius;
};
#endif

13
klik/debug.qc Normal file
View file

@ -0,0 +1,13 @@
#include "common.qh"
#include "debug.qh"
void() debug_impulse = {
local float imp;
imp = self.impulse;
self.impulse = 0;
{
self.impulse = imp;
}
};

10
klik/debug.qh Normal file
View file

@ -0,0 +1,10 @@
#ifndef DEBUG_qh
#define DEBUG_qh 1
@extern {
void() debug_impulse;
};
#endif

159
klik/defs.qh Normal file
View file

@ -0,0 +1,159 @@
#ifndef DEFS_qh
#define DEFS_qh 1
#include "config.qh"
// ========================================================================== //
// ========================================================================== //
/* These are defined in the C code */
#define FALSE 0
#define TRUE 1
// edict.flags
#define FL_FLY 1
#define FL_SWIM 2
#define FL_CLIENT 8 /* set for all client edicts */
#define FL_INWATER 16 /* for enter / leave water splash */
#define FL_MONSTER 32
#define FL_GODMODE 64 /* player cheat */
#define FL_NOTARGET 128 /* player cheat */
#define FL_ITEM 256 /* extra wide size for bonus items */
#define FL_ONGROUND 512 /* standing on something */
#define FL_PARTIALGROUND 1024 /* not all corners are valid */
#define FL_WATERJUMP 2048 /* player jumping out of water */
#define FL_JUMPRELEASED 4096 /* for jump debouncing */
// edict.movetype values
#define MOVETYPE_NONE 0 /* never moves */
#define MOVETYPE_ANGLENOCLIP 1 /* NO LONGER SUPPORTED. */
#define MOVETYPE_ANGLECLIP 2 /* NO LONGER SUPPORTED. */
#define MOVETYPE_WALK 3 /* players only */
#define MOVETYPE_STEP 4 /* discrete, not real time unless fall */
#define MOVETYPE_FLY 5
#define MOVETYPE_TOSS 6 /* gravity */
#define MOVETYPE_PUSH 7 /* no clip to world, push and crush */
#define MOVETYPE_NOCLIP 8
#define MOVETYPE_FLYMISSILE 9 /* fly with extra size against monsters */
#define MOVETYPE_BOUNCE 10
#define MOVETYPE_BOUNCEMISSILE 11 /* bounce with extra size */
// edict.solid values
#define SOLID_NOT 0 /* no interaction with other objects */
#define SOLID_TRIGGER 1 /* touch on edge, but not blocking */
#define SOLID_BBOX 2 /* touch on edge, block */
#define SOLID_SLIDEBOX 3 /* touch on edge, but not an onground */
#define SOLID_BSP 4 /* bsp clip, touch on edge, block */
// items
#define IT_AXE 4096
#define IT_SHOTGUN 1
#define IT_SUPER_SHOTGUN 2
#define IT_NAILGUN 4
#define IT_SUPER_NAILGUN 8
#define IT_GRENADE_LAUNCHER 16
#define IT_ROCKET_LAUNCHER 32
#define IT_LIGHTNING 64
#define IT_EXTRA_WEAPON 128
#define IT_SHELLS 256
#define IT_NAILS 512
#define IT_ROCKETS 1024
#define IT_CELLS 2048
#define IT_ARMOR1 8192
#define IT_ARMOR2 16384
#define IT_ARMOR3 32768
#define IT_SUPERHEALTH 65536
#define IT_KEY1 131072
#define IT_KEY2 262144
#define IT_INVISIBILITY 524288
#define IT_INVULNERABILITY 1048576
#define IT_SUIT 2097152
#define IT_QUAD 4194304
// point content values
#define CONTENT_EMPTY -1
#define CONTENT_SOLID -2
#define CONTENT_WATER -3
#define CONTENT_SLIME -4
#define CONTENT_LAVA -5
#define CONTENT_SKY -6
// origin, clipping hull stuff
#define VEC_ORIGIN '0 0 0'
#define VEC_HULL_MIN '-16 -16 -24'
#define VEC_HULL_MAX '16 16 32'
#define VEC_HULL2_MIN '-32 -32 -24'
#define VEC_HULL2_MAX '32 32 64'
// sound channels
// channel 0 never willingly overrides
// other channels (1-7) allways override a playing sound on that channel
#define CHAN_AUTO 0
#define CHAN_WEAPON 1
#define CHAN_VOICE 2
#define CHAN_ITEM 3
#define CHAN_BODY 4
#define CHAN_NO_PHS_ADD 8 /* ie: CHAN_BODY | CHAN_NO_PHS_ADD */
#define ATTN_NONE 0
#define ATTN_NORM 1
#define ATTN_IDLE 2
#define ATTN_STATIC 3
// entity effects
//#define EF_BRIGHTFIELD 1 /* not in QW */
//#define EF_MUZZLEFLASH 2 /* not in QW */
#define EF_BRIGHTLIGHT 4
#define EF_DIMLIGHT 8
#define EF_FLAG1 16
#define EF_FLAG2 32
// GLQuakeWorld Stuff
#define EF_BLUE 64 /* Blue Globe effect for Quad */
#define EF_RED 128 /* Red Globe effect for Pentagram */
// messages
#define MSG_BROADCAST 0 /* unreliable to all */
#define MSG_ONE 1 /* reliable to one (msg_entity) */
#define MSG_ALL 2 /* reliable to all */
#define MSG_INIT 3 /* write to the init string */
#define MSG_MULTICAST 4 /* for multicast() call */
// message levels
#define PRINT_LOW 0 /* pickup messages */
#define PRINT_MEDIUM 1
#define PRINT_DEATH 1 /* death messages */
#define PRINT_HIGH 2 /* critical messages */
#define PRINT_CHAT 3 /* also goes to chat console */
// multicast sets
#define MULTICAST_ALL 0 /* every client */
#define MULTICAST_PHS 1 /* within hearing */
#define MULTICAST_PVS 2 /* within sight */
#define MULTICAST_ALL_R 3 /* every client, reliable */
#define MULTICAST_PHS_R 4 /* within hearing, reliable */
#define MULTICAST_PVS_R 5 /* within sight, reliable */
// ========================================================================== //
// ========================================================================== //
// takedamage values
#define DAMAGE_NO 0
#define DAMAGE_YES 1
#define DAMAGE_AIM 2
// deadflag, the C code doesn't actually use these.
#define DEAD_NO 0
#define DEAD_DYING 1
#define DEAD_DEAD 2
#define DEAD_NONLIVING -1
// Used by me
#define FL_AUTOTHINK FL_CLIENT
#endif

111
klik/delays.qc Normal file
View file

@ -0,0 +1,111 @@
#include "common.qh"
#include "server.qh"
#include "delays.qh"
.float delay_health, delay_armorvalue, delay_currentammo;
.float delay_items, delay_effects;
.float delay_ammo_shells, delay_ammo_nails;
.float delay_ammo_rockets, delay_ammo_cells;
.float delay_dmg_take, delay_dmg_save;
.float delay_time, delay_last_change;
#define all_func(func) \
void() func##_all = { \
local entity oldself; \
local float i; \
\
oldself = self; \
\
self = world; \
for (i = 0; i < max_clients; i++) { \
self = nextent(self); \
\
if (!is_cl(self)) \
continue; \
\
func(); \
} \
\
self = oldself; \
}
#define do_fields() \
do_(health); \
do_(armorvalue); \
do_(currentammo); \
do_(items); \
do_(effects); \
do_(ammo_shells); \
do_(ammo_nails); \
do_(ammo_rockets); \
do_(ammo_cells)
void() delays_swapin_stats = {
local float tmp;
#define do_(field) \
tmp = self.field; \
self.field = self.delay_##field; \
self.delay_##field = tmp
do_fields();
#undef do_
};
all_func(delays_swapin_stats);
// ===================================================================== //
float() delays_changed = {
#define do_(field) \
if (floor(self.field) != floor(self.delay_##field)) \
return TRUE
do_fields();
#undef do_
return FALSE;
};
// ===================================================================== //
void() delays_force_update = {
self.delay_time = 0;
};
all_func(delays_force_update);
// ===================================================================== //
void() delays_swapout_stats = {
if (delays_changed())
self.delay_last_change = time;
self.delay_dmg_take += self.dmg_take; self.dmg_take = 0;
self.delay_dmg_save += self.dmg_save; self.dmg_save = 0;
if (time < self.delay_time) {
delays_swapin_stats();
return;
}
#define do_(field) self.delay_##field = self.field
do_fields();
#undef do_
self.dmg_take = ceil(self.delay_dmg_take); self.delay_dmg_take = 0;
if (self.dmg_take > 255) self.dmg_take = 255;
self.dmg_save = ceil(self.delay_dmg_save); self.delay_dmg_save = 0;
if (self.dmg_save > 255) self.dmg_save = 255;
if ((self.delay_last_change - time) >= -CONFIG_STATS_DELAY)
self.delay_time = time + CONFIG_STATS_DELAY;
};
all_func(delays_swapout_stats);

17
klik/delays.qh Normal file
View file

@ -0,0 +1,17 @@
#ifndef DELAYS_qh
#define DELAYS_qh 1
@extern {
void() delays_swapin_stats;
void() delays_swapout_stats;
void() delays_force_update;
void() delays_swapin_stats_all;
void() delays_swapout_stats_all;
void() delays_force_update_all;
};
#endif

17
klik/effect.qh Normal file
View file

@ -0,0 +1,17 @@
#ifndef EFFECT_qh
#define EFFECT_qh 1
@extern {
void() effect_muzzleflash;
void(entity e) effect_smallkick;
void(vector org, vector dir, float d) effect_blood;
void(vector org, vector vel, float d) effect_gun_spark;
void(vector org, vector vel) effect_nail_spark;
void(vector org) effect_explosion;
void(vector org) effect_teleport_fog;
void(entity from, vector p1, vector p2) effect_lightning2;
};
#endif

103
klik/entnum.qc Normal file
View file

@ -0,0 +1,103 @@
#include "common.qh"
#include "server.qh"
#include "entnum.qh"
/* This is a horrible hack. */
float(entity e) entnum = {
local entity walk, walk2;
local float en, tot;
if (!e)
return 0;
en = 1;
walk = nextent(world);
for (tot = 1; tot <= max_clients; tot++) {
if (e == walk)
return tot;
walk = walk.chain = nextent(walk);
}
while (walk) {
tot++;
walk = walk.chain = nextent(walk);
}
walk = nextent(world);
spawn("__ENTNUM_TEMP__");
for (en = 1; en < tot; en++) {
if (e == walk) {
foreach(classname, "__ENTNUM_TEMP__", remove);
return en;
}
walk2 = nextent(walk);
if (walk.chain != walk2) {
spawn("__ENTNUM_TEMP__");
walk2.chain = walk.chain;
walk.chain = walk2;
tot++;
}
walk = walk2;
if (!walk)
break;
}
error("entnum: Invalid entity\n");
};
entity(float num) entfornum = {
local entity walk, walk2;
local float tot;
local float debugnum;
debugnum = num;
tot = 0;
for (walk = world; tot < max_clients; walk = nextent(walk)) {
if (!num)
return walk;
num--;
tot++;
}
if (!num)
return walk;
tot = 0;
for (walk2 = walk; walk2; walk2 = walk2.chain = nextent(walk2))
tot++;
spawn("__ENTNUM_TEMP__");
for (0; tot; tot--) {
walk2 = nextent(walk);
if (walk.chain != walk2) {
spawn("__ENTNUM_TEMP__");
walk2.chain = walk.chain;
walk.chain = walk2;
tot++;
}
walk = walk2;
num--;
if (!num) {
foreach(classname, "__ENTNUM_TEMP__", remove);
return walk;
}
}
error("entfornum: Invalid entity number: ", ftos(debugnum), "\n");
};
string(entity e) etos = {
return ftos(entnum(e));
};

13
klik/entnum.qh Normal file
View file

@ -0,0 +1,13 @@
#ifndef ENTNUM_qh
#define ENTNUM_qh 1
@extern {
float(entity e) entnum;
entity(float num) entfornum;
string(entity e) etos;
};
#endif

74
klik/equip.qc Normal file
View file

@ -0,0 +1,74 @@
#include "common.qh"
#include "equip.qh"
#include "math.qh"
float(entity e, float eid) equip_flag = {
if (eid < 24) {
e.itemfield = itemfield_1;
} else if (eid < 48) {
e.itemfield = itemfield_2;
eid -= 24;
} else if (eid < 72) {
e.itemfield = itemfield_3;
eid -= 48;
} else if (eid < 96) {
e.itemfield = itemfield_4;
eid -= 72;
}
return shl(1, eid); /* FIXME: use (1 << eid) when the compiler isn't b0rk */
};
float(entity e, float eid) equip_query = {
eid = equip_flag(e, eid);
if (e.(e.itemfield) & eid)
return TRUE;
else
return FALSE;
};
float(entity e, float eid) equip_grant = {
eid = equip_flag(e, eid);
if (e.(e.itemfield) & eid)
return FALSE;
e.(e.itemfield) |= eid;
return TRUE;
};
float(entity e, float eid) equip_remove = {
eid = equip_flag(e, eid);
if (e.(e.itemfield) & eid) {
e.(e.itemfield) -= eid;
return TRUE;
}
return FALSE;
};
float _equip_iter_id;
/* Returns EQUIPID_* or -1 when done */
float(entity iteme) equip_iter = {
local float ret, flag;
while (1) {
if (_equip_iter_id >= EQUIPID_LAST) {
_equip_iter_id = 0;
return -1;
}
flag = equip_flag(iteme, _equip_iter_id);
ret = _equip_iter_id;
_equip_iter_id++;
if (iteme.(iteme.itemfield) & flag)
return ret;
}
return -1; /* Keep compiler from complaining */
};

31
klik/equip.qh Normal file
View file

@ -0,0 +1,31 @@
#ifndef EQUIP_qh
#define EQUIP_qh 1
#include "equipid.qh"
@extern {
#define EQUIP_STATE_CHOOSE 0
#define EQUIP_STATE_CHOSEN 1
.float equip_state;
..float itemfield;
.float itemfield_1;
.float itemfield_2;
.float itemfield_3;
.float itemfield_4;
float(entity e, float eid) equip_flag;
float(entity e, float eid) equip_query;
float(entity e, float eid) equip_grant;
float(entity e, float eid) equip_remove;
float(entity iteme) equip_iter;
string(float eid) equip_id_to_string;
};
#endif

37
klik/equipid_gen.pl Executable file
View file

@ -0,0 +1,37 @@
#!/usr/bin/perl
my ($pos, %equipids);
$pos = 0;
while (<>) {
while (s/^(\s*#\s*define\s+STR_(EQUIPID_[A-Z_]+)\s+(.*))$//) {
next if defined($equipids{$2});
print "$1\n";
$equipids{$2} = $pos;
$pos++;
}
}
while (($key, $value) = each %equipids) {
print "#define $key $value\n";
}
print "#define EQUIPID_LAST $pos\n";
open(HANDLE, ">equipid.qc");
print HANDLE <<EOF;
#include "common.qh"
#include "equip.qh"
EOF
print HANDLE "\nstring(float eid) equip_id_to_string = {\n";
while (($key, $value) = each %equipids) {
print HANDLE "\tif (eid == $key) return STR_$key;\n";
}
print HANDLE "\n\terror(\"Unknown EQUIPID\");\n\treturn \"BUG\";\n};\n";
close(HANDLE);

520
klik/mapents/id_compat.qc Normal file
View file

@ -0,0 +1,520 @@
#include "common.qh"
#include "mapents_util.qh"
#include "items.qh"
#include "mapents_triggers.qh"
#include "mapents_items.qh"
#include "mapents_movewall.qh"
#include "equip.qh"
// ===============================================================
/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
Used as a positional target for spotlights, etc.
*/
void() info_null = { remove(self); };
// ===============================================================
/*QUAKED light_fluoro (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
Non-displayed light.
Default light value is 300
Default style is 0
If targeted, it will toggle between on or off.
Makes steady fluorescent humming sound
*/
void() light_fluoro = {
self.noise = "ambience/fl_hum1.wav";
light();
};
/*QUAKED light_fluorospark (0 1 0) (-8 -8 -8) (8 8 8)
Non-displayed light.
Default light value is 300
Default style is 10
Makes sparking, broken fluorescent sound
*/
void() light_fluorospark = {
if (!self.style)
self.style = 10;
self.noise = "ambience/buzz1.wav";
light();
};
/*QUAKED light_globe (0 1 0) (-8 -8 -8) (8 8 8)
Sphere globe light.
Default light value is 300
Default style is 0
*/
void() light_globe = {
self.model = "progs/s_light.spr";
light();
};
/*QUAKED light_torch_small_walltorch (0 .5 0) (-10 -10 -20) (10 10 20)
Short wall torch
Default light value is 200
Default style is 0
*/
void() light_torch_small_walltorch = {
self.model = "progs/flame.mdl";
self.noise = "ambience/fire1.wav";
light();
};
/*QUAKED light_flame_large_yellow (0 1 0) (-10 -10 -12) (12 12 18)
Large yellow flame ball
*/
void() light_flame_large_yellow = {
self.model = "progs/flame2.mdl";
self.frame = 1;
self.noise = "ambience/fire1.wav";
light();
};
/*QUAKED light_flame_small_yellow (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
Small yellow flame ball
*/
void() light_flame_small_yellow = {
self.model = "progs/flame2.mdl";
self.noise = "ambience/fire1.wav";
light();
};
/*QUAKED light_flame_small_white (0 1 0) (-10 -10 -40) (10 10 40) START_OFF
Small white flame ball
*/
void() light_flame_small_white = {
self.model = "progs/flame2.mdl";
self.noise = "ambience/fire1.wav";
light();
};
// ====================================================================
/*QUAKED misc_explobox2 (0 .5 .8) (0 0 0) (32 32 64)
Smaller exploding box, REGISTERED ONLY
*/
void() misc_explobox2 = {
self.model = "maps/b_exbox2.bsp";
self.noise = "weapons/r_exp3.wav";
self.dmg = 160;
if (!self.mins && !self.maxs) {
self.mins = '0 0 0';
self.maxs = '32 32 32';
}
misc_explobox();
};
// ====================================================================
/*QUAKED ambient_suck_wind (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
*/
void() ambient_suck_wind = {
self.noise = "ambience/suck1.wav";
self.volume = 1.0;
info_notnull();
};
/*QUAKED ambient_drone (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
*/
void() ambient_drone = {
self.noise = "ambience/drone6.wav";
info_notnull();
};
/*QUAKED ambient_flouro_buzz (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
*/
void() ambient_flouro_buzz = {
self.noise = "ambience/buzz1.wav";
self.volume = 1.0;
info_notnull();
};
/*QUAKED ambient_drip (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
*/
void() ambient_drip = {
self.noise = "ambience/drip1.wav";
info_notnull();
};
/*QUAKED ambient_comp_hum (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
*/
void() ambient_comp_hum = {
self.noise = "ambience/comp1.wav";
self.volume = 1.0;
info_notnull();
};
/*QUAKED ambient_thunder (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
*/
void() ambient_thunder = {
self.noise = "ambience/thunder1.wav";
info_notnull();
};
/*QUAKED ambient_light_buzz (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
*/
void() ambient_light_buzz = {
self.noise = "ambience/fl_hum1.wav";
info_notnull();
};
/*QUAKED ambient_swamp1 (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
*/
void() ambient_swamp1 = {
self.noise = "ambience/swamp1.wav";
info_notnull();
};
/*QUAKED ambient_swamp2 (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
*/
void() ambient_swamp2 = {
self.noise = "ambience/swamp2.wav";
info_notnull();
};
// ===========================================================================
void() path_corner = { info_notnull(); };
// ===========================================================================
/*QUAKED trigger_multiple (.5 .5 .5) ? notouch
Variable sized repeatable trigger. Must be targeted at one or more entities.
If "health" is set, the trigger must be killed to activate each time.
If "delay" is set, the trigger waits some time after activating before firing.
"wait" : Seconds between triggerings. (.2 default)
If notouch is set, the trigger is only fired by other entities, not by touching.
NOTOUCH has been obsoleted by trigger_relay!
sounds
1) secret
2) beep beep
3) large switch
4)
set "message" to text string
*/
void() trigger_multiple = {
if (self.sounds == 1) self.noise1 = "misc/secret.wav";
else if (self.sounds == 2) self.noise1 = "misc/talk.wav";
else if (self.sounds == 3) self.noise1 = "misc/trigger1.wav";
trigger_generic();
if (!self.wait) self.wait = 0.2;
self.count = 0;
};
/*QUAKED trigger_once (.5 .5 .5) ? notouch
*/
void() trigger_once = {
trigger_multiple();
self.count = 1;
};
/*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
*/
void() trigger_relay = {
self.spawnflags |= SPAWNFLAGS_TRIGGER_NOTOUCH;
trigger_multiple();
};
#define SPAWNFLAGS_NOMESSAGE 1
void() _trigger_counter_use = {
local float doprint;
doprint = !(self.spawnflags & SPAWNFLAGS_NOMESSAGE) && is_cl(other);
self.count--;
if (self.count <= 0) {
if (doprint) centerprint(other, "Sequence completed!");
self.count = self.max_health;
util_use_targets();
} else {
if (doprint) {
if (self.count > 3)
centerprint(other, "There are more to go...");
else if (self.count > 2)
centerprint(other, "Only 3 more to go...");
else if (self.count > 1)
centerprint(other, "Only 2 more to go...");
else
centerprint(other, "Only 1 more to go...");
}
}
};
/*QUAKED trigger_counter (.5 .5 .5) ? SPAWNFLAGS_NOMESSAGE
Wait decrease count by 1 until it reaches 0, then activate targets.
*/
void() trigger_counter = {
util_map_entity_init();
self.model = NULL_string;
self.modelindex = 0;
if (!self.count)
self.count = 2;
self.use = _trigger_counter_use;
self.think = util_map_entity_cull;
self.nextthink = time + 0.1;
};
/*QUAKED trigger_secret (.5 .5 .5) ?
*/
void() trigger_secret = {
if (!self.message) self.message = "You found a secret area!";
if (!self.sounds) self.sounds = 1;
if (self.sounds > 2) self.sounds = 0;
trigger_multiple();
self.count = 1;
};
/*QUAKED trigger_setskill (.5 .5 .5) ?
sets skill level to the value of "message".
Only used on start map.
*/
void() trigger_setskill = { remove(self); };
/*QUAKED trigger_onlyregistered (.5 .5 .5) ?
Only fires if playing the registered version, otherwise prints the message
*/
void() trigger_onlyregistered = {
self.message = "";
self.wait = -1;
trigger_generic();
};
/*QUAKED trigger_monsterjump (.5 .5 .5) ?
Walking monsters that touch this will jump in the direction of the trigger's angle
"speed" default to 200, the speed thrown forward
"height" default to 200, the speed thrown upwards
*/
void() trigger_monsterjump = { remove(self); };
/*QUAKED func_episodegate (0 .5 .8) ? E1 E2 E3 E4
This bmodel will appear if the episode has allready been completed, so players can't reenter it.
*/
void() func_episodegate = {
if (!(serverflags & self.spawnflags)) {
remove(self);
return;
}
func_wall();
};
/*QUAKED func_bossgate (0 .5 .8) ?
This bmodel appears unless players have all of the episode sigils.
*/
void() func_bossgate = {
if ((serverflags & 15) == 15) {
remove(self);
return;
}
func_wall();
};
/* Monsters */
void() monster_boss = { remove(self); };
void() monster_demon1 = { remove(self); };
void() monster_dog = { remove(self); };
void() monster_enforcer = { remove(self); };
void() monster_fish = { remove(self); };
void() monster_hell_knight = { remove(self); };
void() monster_knight = { remove(self); };
void() monster_ogre = { remove(self); };
void() monster_ogre_marksman = { remove(self); };
void() monster_oldone = { remove(self); };
void() monster_shalrath = { remove(self); };
void() monster_shambler = { remove(self); };
void() monster_army = { remove(self); };
void() monster_tarbaby = { remove(self); };
void() monster_wizard = { remove(self); };
void() monster_zombie = { remove(self); };
// =========================================================================
void() item_weapon = {
if (!self.noise2) self.noise2 = "weapons/pkup.wav";
if (!self.mins && !self.maxs) {
self.mins = '-16 -16 0';
self.maxs = '16 16 56';
}
if (!self.wait && !self.delay) {
self.wait = 25;
self.delay = 10;
}
item_generic();
};
/*QUAKED weapon_supershotgun (0 .5 .8) (-16 -16 0) (16 16 32)
*/
void() weapon_supershotgun = {
self.netname = STR_EQUIPID_SUPER_SHOTGUN;
if (!self.model) self.model = "progs/g_shot.mdl";
if (!self.ammo_shells) self.ammo_shells = 5;
equip_grant(self, EQUIPID_SUPER_SHOTGUN);
item_weapon();
};
/*QUAKED weapon_nailgun (0 .5 .8) (-16 -16 0) (16 16 32)
*/
void() weapon_nailgun = {
self.netname = STR_EQUIPID_NAILGUN;
if (!self.model) self.model = "progs/g_nail.mdl";
if (!self.ammo_nails) self.ammo_nails = 30;
equip_grant(self, EQUIPID_NAILGUN);
item_weapon();
};
/*QUAKED weapon_supernailgun (0 .5 .8) (-16 -16 0) (16 16 32)
*/
void() weapon_supernailgun = {
self.netname = STR_EQUIPID_SUPER_NAILGUN;
if (!self.model) self.model = "progs/g_nail2.mdl";
if (!self.ammo_nails) self.ammo_nails = 30;
equip_grant(self, EQUIPID_SUPER_NAILGUN);
item_weapon();
};
/*QUAKED weapon_grenadelauncher (0 .5 .8) (-16 -16 0) (16 16 32)
*/
void() weapon_grenadelauncher = {
self.netname = STR_EQUIPID_GRENADE_LAUNCHER;
if (!self.model) self.model = "progs/g_rock.mdl";
if (!self.ammo_rockets) self.ammo_rockets = 5;
equip_grant(self, EQUIPID_GRENADE_LAUNCHER);
item_weapon();
};
/*QUAKED weapon_rocketlauncher (0 .5 .8) (-16 -16 0) (16 16 32)
*/
void() weapon_rocketlauncher = {
self.netname = STR_EQUIPID_ROCKET_LAUNCHER;
if (!self.model) self.model = "progs/g_rock2.mdl";
if (!self.ammo_rockets) self.ammo_rockets = 5;
equip_grant(self, EQUIPID_ROCKET_LAUNCHER);
item_weapon();
};
/*QUAKED weapon_lightning (0 .5 .8) (-16 -16 0) (16 16 32)
*/
void() weapon_lightning = {
self.netname = STR_EQUIPID_LIGHTNING_GUN;
if (!self.model) self.model = "progs/g_light.mdl";
if (!self.ammo_cells) self.ammo_cells = 15;
equip_grant(self, EQUIPID_LIGHTNING_GUN);
item_weapon();
};
// ========================================================================
#define SPAWNFLAGS_AMMO_BIG 1
/*QUAKED item_shells (0 .5 .8) (0 0 0) (32 32 32) BIG
*/
void() item_shells = {
if (self.spawnflags & SPAWNFLAGS_AMMO_BIG) {
self.model = "maps/b_shell1.bsp";
self.ammo_shells = 40;
} else {
self.model = "maps/b_shell0.bsp";
self.ammo_shells = 20;
}
item_ammo();
};
/*QUAKED item_spikes (0 .5 .8) (0 0 0) (32 32 32) BIG
*/
void() item_spikes = {
if (self.spawnflags & SPAWNFLAGS_AMMO_BIG) {
self.model = "maps/b_nail1.bsp";
self.ammo_nails = 50;
} else {
self.model = "maps/b_nail0.bsp";
self.ammo_nails = 25;
}
item_ammo();
};
/*QUAKED item_rockets (0 .5 .8) (0 0 0) (32 32 32) BIG
*/
void() item_rockets = {
if (self.spawnflags & SPAWNFLAGS_AMMO_BIG) {
self.model = "maps/b_rock1.bsp";
self.ammo_rockets = 10;
} else {
self.model = "maps/b_rock0.bsp";
self.ammo_rockets = 5;
}
item_ammo();
};
/*QUAKED item_cells (0 .5 .8) (0 0 0) (32 32 32) BIG
*/
void() item_cells = {
if (self.spawnflags & SPAWNFLAGS_AMMO_BIG) {
self.model = "maps/b_batt1.bsp";
self.ammo_cells = 12;
} else {
self.model = "maps/b_batt0.bsp";
self.ammo_cells = 6;
}
item_ammo();
};
// ========================================================================
/*QUAKED item_armor1 (0 .5 .8) (-16 -16 0) (16 16 32)
*/
void() item_armor1 = {
self.skin = 0;
self.armorvalue = 100;
self.armortype = 0.3;
item_armor();
};
/*QUAKED item_armor2 (0 .5 .8) (-16 -16 0) (16 16 32)
*/
void() item_armor2 = {
self.skin = 1;
self.armorvalue = 150;
self.armortype = 0.6;
item_armor();
};
/*QUAKED item_armorInv (0 .5 .8) (-16 -16 0) (16 16 32)
*/
void() item_armorInv = {
self.skin = 2;
self.armorvalue = 200;
self.armortype = 0.8;
item_armor();
};
// ========================================================================
/*QUAKED misc_teleporttrain (0 .5 .8) (-8 -8 -8) (8 8 8)
*/
void() misc_teleporttrain = {
self.model = "progs/teleport.mdl";
self.dmg = -1;
self.avelocity = '100 200 300';
func_train();
};

67
klik/mapents/items.qc Normal file
View file

@ -0,0 +1,67 @@
#include "common.qh"
#include "mapents_util.qh"
#include "misc.qh"
#include "items.qh"
void() _item_regen_think = {
self.solid = SOLID_TRIGGER;
setmodel(self, self.model);
sound(self, CHAN_VOICE, self.noise7, 1, ATTN_NORM);
};
void() item_remove_regen = {
local float del;
self.solid = SOLID_NOT;
self.modelindex = 0;
del = self.wait + random()*self.delay;
if (del <= 0) {
safe_remove(self);
return;
}
self.think = _item_regen_think;
self.nextthink = time + del;
};
void() item_generic_touch = {
if (!other.th_takeitem)
return;
if (!util_check_targets()) return;
if (!switcheroo(other, self, other.th_takeitem))
return;
util_use_targets();
item_remove_regen();
};
void() item_generic = {
if (!self.noise7)
self.noise7 = "items/itembk2.wav";
if (sv_spawning)
precache_sound(self.noise7);
self.solid = SOLID_TRIGGER;
self.touch = item_generic_touch;
util_map_entity_init();
self.flags |= FL_ITEM;
if (!self.wait && !self.delay) {
self.wait = 20;
self.delay = 5;
}
if (sv_spawning) {
self.think = util_map_entity_drop;
self.nextthink = time + 0.2; // Let everything else drop to floor.
}
};

10
klik/mapents/items.qh Normal file
View file

@ -0,0 +1,10 @@
#ifndef ITEMS_qh
#define ITEMS_qh 1
void() item_generic_touch;
void() item_generic;
void() item_remove_regen;
.float() th_takeitem;
#endif

273
klik/mapents/mapents.qc Normal file
View file

@ -0,0 +1,273 @@
#include "common.qh"
#include "mapents_util.qh"
#include "damage.qh"
/*QUAKED info_intermission (1 0.5 0.5) (-16 -16 -16) (16 16 16)
This is the camera point for the intermission.
Use mangle instead of angle, so you can set pitch or roll as well as yaw. 'pitch roll yaw'
*/
void() _intermission_loop_chain = {
self.enemy = intermission_head;
};
void() info_intermission = {
util_map_entity_init();
if (!intermission_head) {
self.think = _intermission_loop_chain;
self.nextthink = time;
}
self.enemy = intermission_head;
intermission_head = self;
};
void() _spawn_point_loop_chain = {
self.enemy = spawn_head;
};
void() _spawn_point_init = {
local entity oldself;
util_map_entity_init();
if (self.count > spawn_head.count) {
oldself = self;
while (spawn_head) {
self = spawn_head;
util_map_entity_cull();
spawn_head = spawn_head.enemy;
}
self = oldself;
} else if (self.count < spawn_head.count) {
util_map_entity_cull();
return;
}
if (!spawn_head) {
self.think = _spawn_point_loop_chain;
self.nextthink = time;
}
self.enemy = spawn_head;
spawn_head = self;
};
/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 24)
The single player starting point for a level.
*/
void() info_player_start = { self.count = 0; _spawn_point_init(); };
/*QUAKED info_player_start2 (1 0 0) (-16 -16 24) (16 16 24)
Only used on start map for the return point from an episode.
*/
void() info_player_start2 = { self.count = 0; _spawn_point_init(); };
/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 24)
A spawn point for non-teamplay deathmatch games
*/
void() info_player_deathmatch = { self.count = 100; _spawn_point_init(); };
/*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 24)
A spawn point for coop games
*/
void() info_player_coop = { self.count = 0; _spawn_point_init(); };
/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
Doesn't do anything. Use it for ambients.
*/
void() info_notnull = {
util_map_entity_init();
util_map_entity_cull();
};
#define SPAWNFLAGS_START_OFF 1
/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
Non-displayed light.
Default light value is 300
Default style is 0
If targeted, it will toggle between on or off.
*/
void() _light_use = {
if (self.spawnflags & SPAWNFLAGS_START_OFF) {
lightstyle(self.style, self.noise4);
self.spawnflags -= SPAWNFLAGS_START_OFF;
} else {
lightstyle(self.style, self.noise3);
self.spawnflags |= SPAWNFLAGS_START_OFF;
}
};
void() light = {
util_map_entity_init();
if (!self.noise3) self.noise3 = "a";
if (!self.noise4) self.noise4 = "m";
self.use = _light_use;
if (self.spawnflags & SPAWNFLAGS_START_OFF)
lightstyle(self.style, self.noise3);
else
lightstyle(self.style, self.noise4);
util_map_entity_cull();
};
/*QUAKED misc_fireball (0 .5 .8) (-8 -8 -8) (8 8 8)
Lava Balls
*/
void() _misc_fireball_deathmsg = {
local float r;
local string nname;
r = random();
nname = name(self);
if (r < 0.25) bprint(PRINT_DEATH, nname, " catches a lava ball.\n");
else if (r < 0.5) bprint(PRINT_DEATH, "A lavaball gives ", nname, " a hug.\n");
else if (r < 0.75) bprint(PRINT_DEATH, nname, " was struck down by the lava gods.\n");
else bprint(PRINT_DEATH, nname, " gets coated with liquid brimstone.\n");
};
void() _misc_fireball_touch = {
damage(other, self, self, 20, _misc_fireball_deathmsg);
safe_remove(self);
};
void() _misc_fireball_think = {
local entity fireball;
local vector dir;
fireball = spawn("FIREBALL");
fireball.netname = "a lavaball";
setmodel(fireball, self.weaponmodel);
setorigin(fireball, self.origin);
fireball.solid = SOLID_TRIGGER;
fireball.movetype = MOVETYPE_TOSS;
fireball.touch = _misc_fireball_touch;
makevectors(self.angles);
dir = v_forward*500 + v_right*crandom()*50 + v_up*crandom()*50;
dir = normalize(dir);
fireball.velocity = dir * self.speed;
fireball.mass = 20;
self.nextthink = time + (random() * 5) + 3;
};
void() misc_fireball = {
util_map_entity_init();
if (!self.angles) self.angles = '-90 0 0';
if (!self.speed) self.speed = 200;
if (!self.weaponmodel) self.weaponmodel = "progs/lavaball.mdl";
precache_model(self.weaponmodel);
self.think = _misc_fireball_think;
self.nextthink = time + (random() * 5);
};
/*QUAKED misc_explobox (0 .5 .8) (0 0 0) (32 32 64)
Exploding box.
*/
void() _misc_explobox_deathmsg = {
local float r;
local string nname;
nname = name(self);
r = random();
if (self.dmg_attacker.dmg_attacker == self) {
if (r < 0.5) bprint(PRINT_DEATH, nname, " learns what combustible means the hard way.\n");
else bprint(PRINT_DEATH, nname, " trips on some live ammo.\n");
} else {
if (r < 0.5) bprint(PRINT_DEATH, nname, " has fun at the gunpowder factory.\n");
else bprint(PRINT_DEATH, nname, " eats ", name(self.dmg_attacker.dmg_attacker), "'s box of joy.\n");
}
};
float(float d)
_misc_explobox_damage = {
self.health -= d;
if (self.health <= 0) {
util_use_targets();
self.takedamage = DAMAGE_NO;
self.velocity = '0 0 0';
damage_attack(self);
damage_radius(self, self.dmg_attacker, self, _misc_explobox_deathmsg);
effect_explosion(center(self));
deathmsg_nodisplay();
remove(self);
}
deathmsg_nodisplay();
return FALSE; // lie
};
void() misc_explobox = {
if (!self.model) self.model = "maps/b_explob.bsp";
if (!self.mins && !self.maxs) {
self.mins = '0 0 0';
self.maxs = '32 32 64';
}
self.solid = SOLID_BBOX;
self.movetype = MOVETYPE_NONE;
util_map_entity_init();
if (!self.health) self.health = 20;
if (!self.dmg) self.dmg = 160;
if (!self.mass) self.mass = self.dmg * 8;
if (!self.lip) self.lip = self.dmg;
if (!self.speed) self.speed = 1000;
self.netname = "combustible cargo";
self.takedamage = DAMAGE_AIM;
self.max_health = self.health; // for respawn.
util_map_entity_drop();
self.th_takedamage = _misc_explobox_damage;
};
/*QUAKED func_wall (0 .5 .8) ?
This is just a solid wall if not inhibitted
*/
void() _func_wall_use = { self.frame = 1 - self.frame; };
void() func_wall = {
self.movetype = MOVETYPE_PUSH;
self.solid = SOLID_BSP;
util_map_entity_init();
self.use = _func_wall_use;
util_map_entity_cull();
};
/*QUAKED func_illusionary (0 .5 .8) ?
A simple entity that looks solid but lets you walk through it.
*/
void() func_illusionary = {
self.movetype = MOVETYPE_NONE;
self.solid = SOLID_NOT;
util_map_entity_init();
self.use = _func_wall_use;
util_map_entity_cull();
};

View file

@ -0,0 +1,64 @@
#include "common.qh"
#include "mapents_util.qh"
#include "items.qh"
#include "mapents_items.qh"
#define SPAWNFLAGS_HEALTH_ROTTEN 1
#define SPAWNFLAGS_HEALTH_MEGA 2
/*QUAKED item_health (.3 .3 1) (0 0 0) (32 32 32) ROTTEN MEGA
Health box. Normally gives 25 points.
Rotten box heals 5-10 points,
megahealth will add 100 health, then
rot you down to your maximum health limit,
one point per second.
*/
void() item_megahealth;
void() item_health = {
if (self.spawnflags & SPAWNFLAGS_HEALTH_ROTTEN) {
self.model = "maps/b_bh10.bsp";
self.noise2 = "items/r_item1.wav";
self.health = 15;
} else if (self.spawnflags & SPAWNFLAGS_HEALTH_MEGA) {
item_megahealth();
return;
} else {
if (!self.model) self.model = "maps/b_bh25.bsp";
if (!self.noise2) self.noise2 = "items/health1.wav";
if (!self.health) self.health = 25;
}
if (self.mins == '0 0 0' && self.maxs == '0 0 0')
setsize(self, '0 0 0', '32 32 56');
item_generic();
};
/*QUAKED item_armor (0 .5 .8) (-16 -16 0) (16 16 32)
*/
void() item_armor = {
if (!self.model) self.model = "progs/armor.mdl";
if (!self.noise2) self.noise2 = "items/armor1.wav";
if (self.mins == '0 0 0' && self.maxs == '0 0 0')
setsize(self, '-16 -16 0', '16 16 56');
item_generic();
};
// ========================================================================
/*QUAKED item_ammo (0 .5 .8) (0 0 0) (32 32 32)
*/
void() item_ammo = {
if (!self.model) self.model = "progs/backpack.mdl";
if (!self.noise2) self.noise2 = "weapons/lock4.wav";
if (self.mins == '0 0 0' && self.maxs == '0 0 0')
setsize(self, '0 0 0', '32 32 56');
if (!self.wait && !self.delay) {
self.wait = 25;
self.delay = 10;
}
item_generic();
};

View file

@ -0,0 +1,7 @@
#ifndef MAPENTS_ITEMS_qh
#define MAPENTS_ITEMS_qh 1
void() item_armor;
void() item_ammo;
#endif

View file

@ -0,0 +1,925 @@
#include "common.qh"
#include "mapents_util.qh"
#include "damage.qh"
#include "mapents_movewall.qh"
/* movewalls! The replacement for doors/plats/trains. */
/* Internally:
when used:
a movewall will start to go self.goalentity.pos2, at
self.goalentity.speed. You may change pos2 when the
state event occurs.
self.state will reflect the current state, the first state
being 0, between the first and second being 0.5, and
increasing to 1 once it reaches the second. it will increase
the same way until it reaches the first goalentity, which is 0.
states are in the goalentity's .style
self.goalentity will be set to self.goalentity.goalentity
a state event will occur.
(state events are triggered by calling self.w_think, if it exists.)
after it reaches the position, self.state will reflect the
self.goalentity.style of the new position, and a state
event will be triggered.
-- snip --
movewalls start with an undefined state (i.e., it will be
0 if it just spawned and you don't set it)
You must provide your own self.blocked function.
You must also provide a means of calling self.use(),
or rely on it being a target.
*/
void() _deathmsg_squish = {
bprint(PRINT_DEATH, name(self), " was squished.\n");
};
.vector finaldest;
void() _move_to_pos_done = {
self.velocity = '0 0 0';
setorigin(self, self.finaldest);
self.nextthink = -1;
if (self.think1)
self.think1();
};
/* calculate velocity and direction to move to position at spd. */
/* _ONLY_ use this with MOVETYPE_PUSH's! */
void(vector position, float spd, void() think_func) util_move_to_pos = {
local vector offs;
local float dist;
self.finaldest = position;
self.speed = spd;
offs = position - self.origin;
dist = vlen(offs);
offs = offs * (1/dist);
self.velocity = offs * spd;
self.think1 = think_func;
self.think = _move_to_pos_done;
self.nextthink = self.ltime + (dist / spd);
if (self.nextthink <= self.ltime)
self.nextthink = self.ltime + sv_mintic;
};
void() _movewall_done = {
self.state = self.state + 0.5;
if (self.w_think)
self.w_think();
};
void() _movewall_use = {
local float spd;
if (!self.goalentity) {
/* Ugh. */
dprint("Activated unfinalized movewall\n");
return;
}
/* Avoid multiple activations per frame */
if (self.origin == self.goalentity.pos2)
return;
spd = self.goalentity.speed;
if (!spd) spd = self.speed;
util_move_to_pos(self.goalentity.pos2 - self.view_ofs, spd, _movewall_done);
self.state = self.goalentity.style - 0.5;
self.goalentity = self.goalentity.goalentity;
if (self.w_think)
self.w_think();
};
void() movewall_init = {
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
self.deadflag = DEAD_NONLIVING;
self.use = _movewall_use;
};
// ========================================================================
/* Two states, no more, no less. pos2 contains the next position. */
/* Plays self.noise3 when starting to move, and self.noise4 when stopping. */
/* damages blocking entities if self.dmg (per second if it doesn't go back) */
/* when state is 1, waits for self.wait seconds, then activates again. */
void() _movewall_wait_think = {
if (self.pain_finished <= self.ltime) {
_movewall_use();
return;
}
self.nextthink = self.pain_finished;
};
void() _movewall_state0_use = {
if (self.state != 0)
return;
_movewall_use();
};
void() _movewall_binary_think = {
if (floor(self.state) != self.state) {
local vector tmp;
if (self.noise3)
sound(self, CHAN_BODY, self.noise3, 1, ATTN_NORM);
tmp = self.pos2;
self.pos2 = self.pos1;
self.pos1 = tmp;
self.style = 1 - self.style;
} else {
if (self.noise4)
sound(self, CHAN_BODY|CHAN_NO_PHS_ADD, self.noise4, 1, ATTN_NORM);
if (self.state == 1) {
self.think = _movewall_wait_think;
self.nextthink = self.ltime + self.wait;
}
}
};
void() _movewall_block_ignore = {
if (self.dmg)
damage(other, self, self, self.dmg*frametime, _deathmsg_squish);
/* recalculate the move.. */
if (self.nextthink && self.think == _movewall_done)
util_move_to_pos(self.finaldest, self.speed, self.think1);
};
void() _movewall_block_goback = {
if (self.dmg)
damage(other, self, self, self.dmg, _deathmsg_squish);
_movewall_use();
};
void() _movewall_trigger_touch = {
self = self.owner;
self.flags = self.flags | FL_JUMPRELEASED;
self.touch();
self.flags = self.flags - FL_JUMPRELEASED;
};
entity(vector org, vector tmin, vector tmax) _movewall_spawn_trigger = {
local entity trigger;
trigger = spawn("TRIGGER");
trigger.solid = SOLID_TRIGGER;
trigger.movetype = MOVETYPE_NONE;
trigger.touch = _movewall_trigger_touch;
trigger.owner = self;
setsize(trigger, tmin, tmax);
setorigin(trigger, org);
return trigger;
};
// ========================================================================
/* doors... state 0 is closed, state 1 is open. */
/* self.owner is the head of a list of linked doors. */
/* self.enemy is the next in the list. */
#define SPAWNFLAGS_DOOR_START_OPEN 1
#define SPAWNFLAGS_DOOR_DONT_LINK 4
#define SPAWNFLAGS_DOOR_GOLD_KEY 8 /* legacy */
#define SPAWNFLAGS_DOOR_SILVER_KEY 16 /* legacy */
#define SPAWNFLAGS_DOOR_TOGGLE 32
float(float d) _movewall_door_takedamage = {
local entity oldself;
if (self.owner.state != 0) {
deathmsg_nodisplay();
return FALSE;
}
oldself = self;
self = self.owner;
self.health -= d;
if (self.health <= 0) {
self.health = self.max_health;
while (self) {
if (util_use_targets()) {
self.use();
/* Hack for id compat... */
/* Use target if you need it to go more
than once */
self.message = "";
self.noise1 = NULL_string;
self.noise2 = NULL_string;
}
self = self.enemy;
}
}
self = oldself;
deathmsg_nodisplay();
return FALSE; /* lie */
};
void() _movewall_door_touch = {
local entity oldself;
if (!is_living(other))
return;
oldself = self;
self = self.owner;
if (self.state != 0) {
while (self) {
self.pain_finished = self.ltime + self.wait;
self = self.enemy;
}
} else {
while (self) {
if (util_use_targets()) {
_movewall_use();
/* Hack for id compat... */
/* Use target if you need it to go more
than once */
self.message = "";
self.noise1 = NULL_string;
self.noise2 = NULL_string;
}
self = self.enemy;
}
}
self = oldself;
};
void() _door_link = {
local entity head, tail;
tail = self;
tail.owner = self;
head = self;
while (1) {
head = find(head, classname, self.classname);
if (!head)
break;
if (head.spawnflags & SPAWNFLAGS_DOOR_DONT_LINK)
continue;
if (!util_entities_touch(self, head))
continue;
if (head.owner != head)
objerror("Crosslinked doors\n");
tail.enemy = head;
tail = head;
tail.nextthink = -1; // Avoid trying to link again.
tail.owner = self;
/* *Sigh*. Id compat. */
if (tail.noise1) self.noise1 = tail.noise1;
if (tail.noise2) self.noise2 = tail.noise2;
if (tail.noise3) self.noise3 = tail.noise3;
if (tail.noise4) self.noise4 = tail.noise4;
if (tail.noise5) self.noise5 = tail.noise5;
if (tail.noise6) self.noise6 = tail.noise6;
if (tail.message) self.message = tail.message;
if (tail.health) self.health = tail.health;
if (tail.targetname) self.targetname = tail.targetname;
tail.message = "";
tail.noise1 = NULL_string;
tail.noise2 = NULL_string;
tail.noise3 = NULL_string;
tail.noise4 = NULL_string;
tail.noise5 = NULL_string;
tail.noise6 = NULL_string;
}
tail.enemy = world;
head = self;
while (self) {
self.health = head.health;
self.targetname = head.targetname;
if (!self.health && !self.targetname) {
if (!self.items) {
local vector tmin, tmax;
tmin = self.mins - '60 60 8';
tmax = self.maxs + '60 60 8';
_movewall_spawn_trigger(self.origin, tmin, tmax);
}
self.touch = _movewall_door_touch;
} else {
if (self.health) {
self.takedamage = DAMAGE_YES;
self.th_takedamage = _movewall_door_takedamage;
}
}
self = self.enemy;
}
self = head;
};
void() func_door = {
if (!self.noise5) {
if (world.worldtype == 0) {
self.noise5 = "doors/medtry.wav";
self.noise6 = "doors/meduse.wav";
} else if (world.worldtype == 1) {
self.noise5 = "doors/runetry.wav";
self.noise6 = "doors/runeuse.wav";
} else if (world.worldtype == 2) {
self.noise5 = "doors/basetry.wav";
self.noise6 = "doors/baseuse.wav";
}
}
if (!self.noise3) {
if (self.sounds == 1) {
self.noise3 = "doors/doormv1.wav";
self.noise4 = "doors/drclos4.wav";
} else if (self.sounds == 2) {
self.noise3 = "doors/hydro1.wav";
self.noise4 = "doors/hydro2.wav";
} else if (self.sounds == 3) {
self.noise3 = "doors/stndr1.wav";
self.noise4 = "doors/stndr2.wav";
} else if (self.sounds == 4) {
self.noise3 = "doors/ddoor1.wav";
self.noise4 = "doors/ddoor2.wav";
}
}
if (self.noise3) precache_sound(self.noise3);
if (self.noise4) precache_sound(self.noise4);
if (self.message != "" && !self.noise1 && !self.noise2)
self.noise2 = "misc/talk.wav";
if (!self.speed) self.speed = 100;
if (!self.wait) self.wait = 3;
if (!self.lip) self.lip = 8;
if (!self.dmg) self.dmg = 2;
if (self.dmg < 0) self.dmg = 0;
if (self.spawnflags & SPAWNFLAGS_DOOR_SILVER_KEY) {
self.spawnflags = self.spawnflags | SPAWNFLAGS_CHECK_ITEMS;
self.items = self.items | IT_KEY1;
self.wait = -1;
}
if (self.spawnflags & SPAWNFLAGS_DOOR_GOLD_KEY) {
self.spawnflags = self.spawnflags | SPAWNFLAGS_CHECK_ITEMS;
self.items = self.items | IT_KEY2;
self.wait = -1;
}
self.max_health = self.health;
movewall_init();
util_map_entity_init();
util_set_movedir();
self.pos1 = self.origin;
self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
if (self.spawnflags & SPAWNFLAGS_DOOR_START_OPEN) {
setorigin(self, self.pos2);
self.pos2 = self.pos1;
self.pos1 = self.origin;
}
self.state = 0;
self.style = 1 - self.state;
self.touch = NOTHING_function;
self.goalentity = self;
self.use = _movewall_door_touch;
self.blocked = _movewall_block_goback;
self.w_think = _movewall_binary_think;
self.owner = self; /* In case we get triggered before 0.1 */
self.think = _door_link;
self.nextthink = self.ltime + 0.1;
};
// ========================================================================
/* plats.. state 0 is the 'top' position, state 1 is 'bottom' */
#define SPAWNFLAGS_PLAT_LOW_TRIGGER 1
void() _movewall_plat_touch = {
if (!(self.flags & FL_JUMPRELEASED))
return;
_movewall_door_touch();
};
void() func_plat = {
local vector tmin, tmax;
if (!self.noise3) {
if (self.sounds == 1) {
self.noise3 = "plats/plat1.wav";
self.noise4 = "plats/plat2.wav";
} else if (self.sounds == 0 || self.sounds == 2) {
self.noise3 = "plats/medplat1.wav";
self.noise4 = "plats/medplat2.wav";
}
}
if (self.noise3) precache_sound(self.noise3);
if (self.noise4) precache_sound(self.noise4);
if (!self.speed) self.speed = 150;
if (!self.wait) self.wait = 1;
movewall_init();
util_map_entity_init();
if (!self.height)
self.height = self.size_z - 8;
self.pos1 = self.origin;
self.pos2 = self.origin;
self.pos2_z = self.pos2_z - self.height;
// =============
tmin = self.mins + '25 25 0';
tmax = self.maxs - '25 25 -8';
tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8);
if (self.spawnflags & SPAWNFLAGS_PLAT_LOW_TRIGGER)
tmax_z = tmin_z + 8;
if (self.size_x <= 50)
tmin_x = (self.mins_x + self.maxs_x) * 0.5 + 1;
if (self.size_y <= 50)
tmin_y = (self.mins_y + self.maxs_y) * 0.5 + 1;
_movewall_spawn_trigger(self.pos1, tmin, tmax);
// =============
if (!self.targetname) {
setorigin(self, self.pos2);
self.pos2 = self.pos1;
self.pos1 = self.origin;
self.style = 1;
} else {
self.style = 0;
}
self.state = 1 - self.style;
self.owner = self;
self.goalentity = self;
self.use = _movewall_plat_touch;
self.touch = _movewall_plat_touch;
self.blocked = _movewall_block_goback;
self.w_think = _movewall_binary_think;
};
// ========================================================================
/* buttons, out pos1, in pos2 */
void() _movewall_button_think = {
if (floor(self.state) != self.state) {
local vector tmp;
if (self.state == 0.5) {
if (self.noise3)
sound(self, CHAN_BODY, self.noise3, 1, ATTN_NORM);
}
tmp = self.pos2;
self.pos2 = self.pos1;
self.pos1 = tmp;
self.style = 1 - self.style;
} else {
if (self.state == 1) {
if (self.noise4)
sound(self, CHAN_BODY|CHAN_NO_PHS_ADD, self.noise4, 1, ATTN_NORM);
self.think = _movewall_wait_think;
if (util_use_targets()) {
self.frame = 1;
self.nextthink = self.ltime + self.wait;
} else {
self.nextthink = self.ltime + 0.5;
}
} else {
self.frame = 0;
}
}
};
void() _movewall_button_touch = {
if (!is_living(other))
return;
if (self.state != 0)
return;
self.use();
};
float(float d) _movewall_button_takedamage = {
deathmsg_nodisplay();
if (self.state != 0)
return FALSE;
self.health -= d;
if (self.health <= 0) {
self.health = self.max_health;
self.use();
}
return FALSE; /* lie */
};
void() func_button = {
if (!self.noise3) {
if (self.sounds == 0) self.noise3 = "buttons/airbut1.wav";
else if (self.sounds == 1) self.noise3 = "buttons/switch21.wav";
else if (self.sounds == 2) self.noise3 = "buttons/switch02.wav";
else if (self.sounds == 3) self.noise3 = "buttons/switch04.wav";
}
if (self.noise3) precache_sound(self.noise3);
if (self.noise4) precache_sound(self.noise4);
if (!self.speed) self.speed = 40;
if (!self.wait) self.wait = 1;
if (!self.lip) self.lip = 4;
movewall_init();
util_map_entity_init();
util_set_movedir();
self.pos1 = self.origin;
self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
self.style = 1;
self.state = 1 - self.style;
if (!self.health && !self.targetname) {
self.touch = _movewall_button_touch;
} else {
if (self.health) {
self.takedamage = DAMAGE_YES;
self.th_takedamage = _movewall_button_takedamage;
}
self.touch = NOTHING_function;
}
self.goalentity = self;
self.blocked = _movewall_block_ignore;
self.w_think = _movewall_button_think;
};
// ========================================================================
#define SPAWNFLAGS_SECRET_ONCE 1
#define SPAWNFLAGS_SECRET_1ST_LEFT 2
#define SPAWNFLAGS_SECRET_1ST_DOWN 4
#define SPAWNFLAGS_SECRET_NO_SHOOT 8
#define SPAWNFLAGS_SECRET_YES_SHOOT 16
/* 'secret door', has several points it moves to. */
/*
state 0 is closed
state 1 is back
state 2 is to the side (fully open)
*/
/* noise3 is played when transitioning */
/* noise4 is played when the transition is complete */
/* pos1 is state 0 position */
void() _movewall_secret_use = {
/* Stay open... */
if (self.count == 2 && self.state == 2)
self.nextthink = self.ltime + self.wait;
if (self.state != 0)
return;
_movewall_use();
};
.vector dest1, dest2;
void() _movewall_secret_think = {
if (floor(self.state) != self.state) {
if (self.count == 0 && self.state == 0.5) {
self.message = NULL_string;
self.noise2 = NULL_string;
if (!util_use_targets()) {
self.velocity = '0 0 0';
setorigin(self, self.pos1);
self.state = 0;
self.nextthink = -1;
return;
}
}
if (self.noise3)
sound(self, CHAN_BODY, self.noise3, 1, ATTN_NORM);
return;
}
if (self.noise4)
sound(self, CHAN_BODY|CHAN_NO_PHS_ADD, self.noise4, 1, ATTN_NORM);
self.think = _movewall_use;
self.nextthink = self.ltime + 1.0;
if (self.count == 0 && self.state == 0) {
self.style = 1;
self.pos2 = self.dest1;
} if (self.count == 0 && self.state == 1) {
self.style = 2;
self.pos2 = self.dest2;
} else if (self.count == 1 && self.state == 2) {
if (self.spawnflags & SPAWNFLAGS_SECRET_ONCE) {
self.nextthink = -1;
} else {
self.style = 1;
self.pos2 = self.dest1;
self.nextthink = self.ltime + self.wait;
}
} else if (self.count == 2 && self.state == 1) {
self.style = 0;
self.pos2 = self.pos1;
} else if (self.count == 1 && self.state == 0) {
self.style = 1;
self.pos2 = self.dest1;
self.nextthink = -1;
}
self.attack_finished = self.nextthink;
self.count = self.state;
};
float(float d) _movewall_secret_takedamage = {
self.use();
deathmsg_nodisplay();
return FALSE;
};
void() _movewall_secret_touch = {
if (!is_living(other))
return;
if (time < self.attack_finished)
return;
self.attack_finished = time + 2;
if (self.message) {
if (is_cl(other))
centerprint(other, self.message);
if (self.noise2)
sound(other, CHAN_ITEM, self.noise2, self.volume, self.attenuation);
}
};
/*QUAKED func_door_secret (0 .5 .8) ? SECRET_ONCE SECRET_1ST_LEFT SECRET_1ST_DOWN SECRET_NO_SHOOT SECRET_YES_SHOOT
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
no_shoot not shootable
yes_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 (default 2)
*/
void() func_door_secret = {
if (!self.noise3) {
if (self.sounds == 1) {
self.noise1 = "doors/latch2.wav";
self.noise3 = "doors/winch2.wav";
self.noise4 = "doors/drclos4.wav";
} else if (self.sounds == 2) {
self.noise3 = "doors/airdoor1.wav";
self.noise4 = "doors/airdoor2.wav";
} else if (self.sounds == 0 || self.sounds == 3) {
self.noise3 = "doors/basesec1.wav";
self.noise4 = "doors/basesec2.wav";
}
}
if (self.message != "" && !self.noise2)
self.noise2 = "misc/talk.wav";
if (self.noise3) precache_sound(self.noise3);
if (self.noise4) precache_sound(self.noise4);
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
if (!self.speed) self.speed = 50;
if (!self.wait) self.wait = 5;
if (!self.dmg) self.dmg = 2;
movewall_init();
util_map_entity_init();
self.use = _movewall_secret_use;
// ===============
util_set_movedir();
if (!self.t_width) {
if (self.spawnflags & 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);
}
self.pos1 = self.origin;
if (self.spawnflags & SPAWNFLAGS_SECRET_1ST_DOWN) {
self.dest1 = self.pos1 - v_up * self.t_width;
} else {
if (self.spawnflags & SPAWNFLAGS_SECRET_1ST_LEFT)
v_right = '0 0 0' - v_right;
self.dest1 = self.pos1 + v_right * self.t_width;
}
self.dest2 = self.dest1 + v_forward * self.t_length;
self.state = 0;
self.style = 1 - self.state;
self.pos2 = self.dest1;
self.sounds = 0;
// ===============
if (!self.targetname || (self.spawnflags & SPAWNFLAGS_SECRET_YES_SHOOT)) {
self.takedamage = DAMAGE_YES;
self.th_takedamage = _movewall_secret_takedamage;
}
self.goalentity = self;
self.blocked = _movewall_block_ignore;
self.touch = _movewall_secret_touch;
self.w_think = _movewall_secret_think;
};
// ========================================================================
/* Trains. Joy. */
void() _movewall_train_think = {
if (floor(self.state) != self.state) {
if (self.count != self.state && self.noise3)
sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
} else {
if (self.noise4)
sound(self, CHAN_VOICE|CHAN_NO_PHS_ADD, self.noise4, 1, ATTN_NORM);
self.think = _movewall_wait_think;
self.nextthink = self.ltime + self.wait;
}
self.count = self.state;
};
void() _train_finalize = {
local entity oldself;
oldself = self;
while (self) {
if (self.goalentity) break; /* Looped. FIXME: Use short circuit when compiler supports */
if (!self.target) objerror("Train without target\n");
self.goalentity = find(world, targetname, self.target);
if (!self.goalentity) objerror("Unable to find train target\n");
self = self.goalentity;
self.pos2 = self.origin;
}
self = oldself;
setorigin(self, self.goalentity.origin - self.view_ofs);
if (!self.targetname) {
self.think = _movewall_wait_think;
self.nextthink = self.ltime + sv_mintic;
}
};
/*QUAKED func_train (0 .5 .8)
*/
void() func_train = {
if (!self.noise3) {
if (self.sounds == 1) {
self.noise3 = "plats/train1.wav";
self.noise4 = "plats/train2.wav";
}
}
if (self.noise3) precache_sound(self.noise3);
if (self.noise4) precache_sound(self.noise4);
if (!self.speed) self.speed = 100;
if (!self.wait) self.wait = 0.1;
if (!self.dmg) self.dmg = 2;
if (self.dmg < 0) self.dmg = 0;
self.view_ofs = self.mins;
self.blocked = _movewall_block_ignore;
self.w_think = _movewall_train_think;
movewall_init();
util_map_entity_init();
/* Make sure all the targetnames are set */
self.think = _train_finalize;
self.nextthink = self.ltime + sv_mintic;
};

View file

@ -0,0 +1,6 @@
#ifndef MAPENTS_MOVEWALL_qh
#define MAPENTS_MOVEWALL_qh 1
void() func_train;
#endif

View file

@ -0,0 +1,544 @@
#include "common.qh"
#include "mapents_util.qh"
#include "items.qh"
#include "override.qh"
#include "damage.qh"
#include "equip.qh"
#include "mapents_powerup.qh"
/* FIXME: These don't handle powerups that grant stuff others grant. */
float(entity powerup) powerup_check_remove = {
if ((self.itemfield_1 & powerup.itemfield_1) != powerup.itemfield_1)
return TRUE;
if ((self.itemfield_2 & powerup.itemfield_2) != powerup.itemfield_2)
return TRUE;
if ((self.itemfield_3 & powerup.itemfield_3) != powerup.itemfield_3)
return TRUE;
if ((self.itemfield_4 & powerup.itemfield_4) != powerup.itemfield_4)
return TRUE;
return FALSE;
};
void(entity powerup) powerup_remove = {
self.itemfield_1 -= (self.itemfield_1 & powerup.itemfield_1);
self.itemfield_2 -= (self.itemfield_2 & powerup.itemfield_2);
self.itemfield_3 -= (self.itemfield_3 & powerup.itemfield_3);
self.itemfield_4 -= (self.itemfield_4 & powerup.itemfield_4);
self.items -= (self.items & powerup.items);
self.effects -= (self.effects & powerup.effects);
override_destroy(self, powerup);
};
float() _powerup_takeitem = {
local entity powerup;
powerup = override_findself();
if ((powerup.itemfield_1 & other.itemfield_1)
|| (powerup.itemfield_2 & other.itemfield_2)
|| (powerup.itemfield_3 & other.itemfield_3)
|| (powerup.itemfield_4 & other.itemfield_4)) {
if ((time+other.attack_finished) > powerup.attack_finished) {
/* Act like we don't have it, to renew.. */
powerup_remove(powerup);
}
}
if (powerup.th_takeitem)
return powerup.th_takeitem();
return FALSE;
};
void() _powerup_prethink = {
local entity powerup;
powerup = override_findself();
if (powerup_check_remove(powerup))
powerup_remove(powerup);
if (powerup.prethink)
powerup.prethink();
};
void() _powerup_think = {
local entity powerup;
powerup = override_findself();
if (time > powerup.attack_finished) {
powerup_remove(powerup);
} else if (time >= powerup.air_finished) {
if (is_cl(self))
stuffcmd(self, "bf\n");
if (powerup.noise) {
sound(self, CHAN_AUTO, powerup.noise, 1, ATTN_NORM);
powerup.noise = NULL_string;
}
powerup.air_finished += 1;
}
if (powerup.actthink)
powerup.actthink();
};
void() _powerup_postthink = {
local entity powerup;
powerup = override_findself();
self.items |= powerup.items;
self.effects |= powerup.effects;
if (powerup.postthink)
powerup.postthink();
};
// ===================================================================== //
float(float dmg) _suit_takedamage = {
local entity powerup;
powerup = override_findself();
if (dmg < DAMAGE_SHOULDDIE && self.dmg_inflictor == world) {
/* Magic formula */
dmg -= 20*frametime;
dmg /= 30*frametime;
if (dmg <= 0) {
override_halt();
deathmsg_nodisplay();
return FALSE;
}
}
if (powerup.th_takedamage)
return powerup.th_takedamage(dmg);
return FALSE;
};
void() _suit_prethink = {
local entity powerup;
powerup = override_findself();
if (powerup_check_remove(powerup)) {
powerup_remove(powerup);
} else {
self.air_finished = time + 12;
}
if (powerup.prethink)
powerup.prethink();
};
#define STR_EQUIPID_SUIT "Environmental Suit"
void() _suit_activate = {
local entity powerup;
powerup = override_create(other, "OVERRIDE_SUIT", OVERPRIO_SUIT);
powerup.th_takeitem = _powerup_takeitem;
powerup.th_takedamage = _suit_takedamage;
powerup.prethink = _suit_prethink;
powerup.actthink = _powerup_think;
powerup.postthink = _powerup_postthink;
override_finalize(powerup);
equip_grant(powerup, EQUIPID_SUIT);
powerup.items = IT_SUIT;
powerup.attack_finished = time + self.attack_finished;
powerup.noise = "items/suit2.wav";
powerup.air_finished = powerup.attack_finished - 3;
};
/*QUAKED item_artifact_envirosuit (0 .5 .8) (-16 -16 -24) (16 16 32)
Player takes no damage from water or slime
*/
void() item_artifact_envirosuit = {
self.netname = STR_EQUIPID_SUIT;
if (!self.model) self.model = "progs/suit.mdl";
if (!self.noise2) self.noise2 = "items/suit.wav";
if (!self.attack_finished) self.attack_finished = 30;
if (!self.mins && !self.maxs) {
self.mins = '-16 -16 -24';
self.maxs = '16 16 32';
}
if (!self.wait && !self.delay) {
self.wait = 55;
self.delay = 10;
}
precache_sound("items/suit2.wav");
equip_grant(self, EQUIPID_SUIT);
self.th_activate = _suit_activate;
item_generic();
};
// ===================================================================== //
void() item_artifact_super_damage;
void() _quad_die = {
local entity powerup;
powerup = override_findself();
if ((powerup.attack_finished - time) >= 4) {
local entity oldself;
oldself = self;
self = spawn("ITEM_ARTIFACT_SUPER_DAMAGE");
self.origin = center(oldself);
self.movetype = MOVETYPE_TOSS;
self.velocity_x = crandom()*200;
self.velocity_y = crandom()*200;
self.velocity_z = 320;
self.wait = -1;
self.attack_finished = powerup.attack_finished - time;
self.think = SUB_remove;
self.nextthink = time + 20 + random()*10;
item_artifact_super_damage();
bprint(PRINT_HIGH, name(oldself), " dropped a Quad with ", ftos(floor(self.attack_finished)), " seconds remaining.\n");
self = oldself;
}
if (powerup.th_die)
powerup.th_die();
};
void(entity missile) _quad_attack = {
local entity powerup;
powerup = override_findself();
if (time >= powerup.pain_finished) {
sound(self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
powerup.pain_finished = time + 1;
}
missile.dmg *= 4;
missile.mass *= 4;
if (powerup.th_attack)
powerup.th_attack(missile);
};
#define STR_EQUIPID_QUAD "Quad Damage"
void() _quad_activate = {
local entity powerup;
powerup = override_create(other, "OVERRIDE_QUAD", OVERPRIO_QUAD);
powerup.th_takeitem = _powerup_takeitem;
powerup.th_attack = _quad_attack;
powerup.th_die = _quad_die;
powerup.prethink = _powerup_prethink;
powerup.actthink = _powerup_think;
powerup.postthink = _powerup_postthink;
override_finalize(powerup);
equip_grant(powerup, EQUIPID_QUAD);
powerup.items = IT_QUAD;
powerup.effects = EF_BLUE;
powerup.attack_finished = time + self.attack_finished;
powerup.noise = "items/damage2.wav";
powerup.air_finished = powerup.attack_finished - 3;
};
/*QUAKED item_artifact_super_damage (0 .5 .8) (-16 -16 -24) (16 16 32)
Attacks from the player will do 4x damage
*/
void() item_artifact_super_damage = {
self.netname = STR_EQUIPID_QUAD;
if (!self.model) self.model = "progs/quaddama.mdl";
if (!self.noise2) self.noise2 = "items/damage.wav";
if (!self.mins && !self.maxs) {
self.mins = '-16 -16 -24';
self.maxs = '16 16 32';
}
if (!self.attack_finished) self.attack_finished = 30;
if (!self.wait && !self.delay) {
self.wait = 55;
self.delay = 10;
}
if (!self.effects) self.effects = EF_BLUE;
if (sv_spawning) {
precache_sound("items/damage3.wav");
precache_sound("items/damage2.wav");
}
equip_grant(self, EQUIPID_QUAD);
self.th_activate = _quad_activate;
item_generic();
};
// ===================================================================== //
float(float dmg) _pentagram_takedamage = {
local entity powerup;
powerup = override_findself();
if (dmg == DAMAGE_MUSTDIE)
return powerup.th_takedamage(dmg);
if (dmg == DAMAGE_SHOULDDIE) {
if (self.dmg_attacker == self)
return powerup.th_takedamage(dmg);
local entity oldattacker, oldinflictor;
local float damaged;
oldattacker = self.dmg_attacker;
oldinflictor = self.dmg_inflictor;
damaged = damage(self.dmg_attacker, self, self.dmg_inflictor, dmg, self.deathmsg);
other = self.dmg_attacker = oldattacker;
oldinflictor = self.dmg_inflictor;
if (!damaged)
return powerup.th_takedamage(dmg);
}
damage_push(dmg);
damage_armor(dmg);
self.dmg_save = 0; // Avoid flashy stuff
if (time >= powerup.pain_finished) {
sound(self, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
powerup.pain_finished = time + 1.0;
}
deathmsg_nodisplay();
override_halt();
return FALSE;
};
#define STR_EQUIPID_PENTAGRAM "Pentagram of Protection"
void() _pentagram_activate = {
local entity powerup;
powerup = override_create(other, "OVERRIDE_PENTAGRAM", OVERPRIO_PENTAGRAM);
powerup.th_takeitem = _powerup_takeitem;
powerup.th_takedamage = _pentagram_takedamage;
powerup.prethink = _powerup_prethink;
powerup.actthink = _powerup_think;
powerup.postthink = _powerup_postthink;
override_finalize(powerup);
equip_grant(powerup, EQUIPID_PENTAGRAM);
powerup.items = IT_INVULNERABILITY;
powerup.effects = EF_RED;
powerup.attack_finished = time + self.attack_finished;
powerup.noise = "items/protect2.wav";
powerup.air_finished = powerup.attack_finished - 3;
};
/*QUAKED item_artifact_invulnerability (0 .5 .8) (-16 -16 -24) (16 16 32)
Player is invulnerable
*/
void() item_artifact_invulnerability = {
self.netname = STR_EQUIPID_PENTAGRAM;
if (!self.model) self.model = "progs/invulner.mdl";
if (!self.noise2) self.noise2 = "items/protect.wav";
if (!self.mins && !self.maxs) {
self.mins = '-16 -16 -24';
self.maxs = '16 16 32';
}
if (!self.attack_finished) self.attack_finished = 30;
if (!self.wait && !self.delay) {
self.wait = 60;
self.delay = 10;
}
if (!self.effects) self.effects = EF_RED;
precache_sound("items/protect3.wav");
precache_sound("items/protect2.wav");
equip_grant(self, EQUIPID_PENTAGRAM);
self.th_activate = _pentagram_activate;
item_generic();
};
// ===================================================================== //
void() _ring_prethink = {
local entity powerup;
powerup = override_findself();
if (powerup_check_remove(powerup)) {
mdl_setup_player();
powerup_remove(powerup);
}
if (powerup.prethink)
powerup.prethink();
};
void() _ring_think = {
local entity powerup;
powerup = override_findself();
if (time > powerup.pain_finished) {
sound(self, CHAN_AUTO, "items/inv3.wav", 0.5, ATTN_IDLE);
powerup.pain_finished = time + 1 + (random() * 3);
}
if (time > powerup.attack_finished) {
mdl_setup_player();
powerup_remove(powerup);
} else if (time >= powerup.air_finished) {
if (is_cl(self))
stuffcmd(self, "bf\n");
if (powerup.noise) {
sound(self, CHAN_AUTO, powerup.noise, 1, ATTN_NORM);
powerup.noise = NULL_string;
}
powerup.air_finished += 1;
}
if (powerup.actthink)
powerup.actthink();
};
#define STR_EQUIPID_RING "Ring of Shadows"
void() _ring_activate = {
local entity powerup, oldself;
powerup = override_create(other, "OVERRIDE_RING", OVERPRIO_RING);
powerup.th_takeitem = _powerup_takeitem;
powerup.prethink = _ring_prethink;
powerup.actthink = _ring_think;
powerup.postthink = _powerup_postthink;
override_finalize(powerup);
equip_grant(powerup, EQUIPID_RING);
powerup.items = IT_INVISIBILITY;
powerup.attack_finished = time + self.attack_finished;
powerup.noise = "items/inv2.wav";
powerup.air_finished = powerup.attack_finished - 3;
oldself = self;
self = other;
mdl_setup_eyes();
self = oldself;
};
/*QUAKED item_artifact_invisibility (0 .5 .8) (-16 -16 -24) (16 16 32)
Player is eyes model
*/
void() item_artifact_invisibility = {
self.netname = STR_EQUIPID_RING;
if (!self.model) self.model = "progs/invisibl.mdl";
if (!self.noise2) self.noise2 = "items/inv1.wav";
if (!self.mins && !self.maxs) {
self.mins = '-16 -16 -24';
self.maxs = '16 16 32';
}
if (!self.attack_finished) self.attack_finished = 30;
if (!self.wait && !self.delay) {
self.wait = 60;
self.delay = 10;
}
precache_sound("items/inv3.wav");
precache_sound("items/inv2.wav");
equip_grant(self, EQUIPID_RING);
self.th_activate = _ring_activate;
item_generic();
};
// ===================================================================== //
float() _megahealth_takeitem = {
local entity powerup;
powerup = override_findself();
if ((powerup.itemfield_1 & other.itemfield_1)
|| (powerup.itemfield_2 & other.itemfield_2)
|| (powerup.itemfield_3 & other.itemfield_3)
|| (powerup.itemfield_4 & other.itemfield_4)) {
if (self.health < (self.max_health*2.5)) {
/* Act like we don't have it, to renew.. */
powerup_remove(powerup);
}
}
if (powerup.th_takeitem)
return powerup.th_takeitem();
return FALSE;
};
void() _megahealth_think = {
local entity powerup;
powerup = override_findself();
if (self.health <= self.max_health) {
powerup_remove(powerup);
} else if (time >= powerup.attack_finished) {
self.health -= 0.1;
if (self.health <= self.max_health) {
self.health = self.max_health;
powerup_remove(powerup);
}
}
if (powerup.actthink)
powerup.actthink();
};
#define STR_EQUIPID_MEGAHEALTH "Megahealth"
void() _megahealth_activate = {
local entity powerup;
powerup = override_create(other, "OVERRIDE_MEGAHEALTH", OVERPRIO_MEGAHEALTH);
powerup.th_takeitem = _megahealth_takeitem;
powerup.prethink = _powerup_prethink;
powerup.actthink = _megahealth_think;
powerup.postthink = _powerup_postthink;
override_finalize(powerup);
equip_grant(powerup, EQUIPID_MEGAHEALTH);
powerup.attack_finished = time + 3;
other.health += self.attack_finished;
if (other.health > (other.max_health*2.5))
other.health = other.max_health*2.5;
};
/*
*/
void() item_megahealth = {
if (!self.model) self.model = "maps/b_bh100.bsp";
if (!self.noise2) self.noise2 = "items/r_item2.wav";
if (!self.mins && !self.maxs) {
self.mins = '0 0 0';
self.maxs = '32 32 56';
}
if (!self.wait && !self.delay) {
self.wait = 30;
self.delay = 40;
}
if (!self.attack_finished) self.attack_finished = 100;
equip_grant(self, EQUIPID_MEGAHEALTH);
self.th_activate = _megahealth_activate;
item_generic();
};

View file

@ -0,0 +1,14 @@
#ifndef MAPENTS_POWERUP_qh
#define MAPENTS_POWERUP_qh 1
#include "math.qh"
#define OVERPRIO_DEFAULT 0
#define OVERPRIO_SUIT OVERPRIO_DEFAULT
#define OVERPRIO_PENTAGRAM (OVERPRIO_SUIT-10)
#define OVERPRIO_QUAD OVERPRIO_DEFAULT
#define OVERPRIO_RING OVERPRIO_DEFAULT
#define OVERPRIO_MEGAHEALTH OVERPRIO_DEFAULT
#endif

View file

@ -0,0 +1,119 @@
#include "common.qh"
#include "mapents_util.qh"
#include "damage.qh"
#include "effect.qh"
#include "misc.qh"
#define SPAWNFLAG_SUPERSPIKE 1
#define SPAWNFLAG_LASER 2
void() _trap_genericshooter_deathmsg = {
bprint(PRINT_DEATH, name(self), " trips a trap.\n");
};
void() _trap_genericshooter_touch = {
if (!damage(other, self.owner, self, self.dmg, _trap_genericshooter_deathmsg)) {
if (self.noise2) sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
effect_nail_spark(self.origin, self.velocity);
}
safe_remove(self);
};
void() _trap_genericshooter_use = {
local entity missile;
if (self.noise1) sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
missile = spawn_missile("TRAP_MISSILE", self.weaponmodel, self.origin, self.movedir, self.speed);
missile.dmg_inflictor = world;
missile.effects |= self.items;
missile.dmg = self.dmg;
deathmsg_copy(self, missile);
missile.noise2 = self.noise2;
missile.touch = _trap_genericshooter_touch;
missile.think = SUB_remove;
missile.nextthink = time + (6000 / self.speed);
};
void() _trap_genericshooter_think = {
self.use();
self.nextthink = time + self.wait;
};
/*QUAKED trap_genericshooter (0 .5 .8) (-8 -8 -8) (8 8 8)
weaponmodel, speed, dmg, items, noise1, noise2
*/
void() trap_genericshooter = {
util_map_entity_init();
if (!self.weaponmodel) {
objerror("trap_genericshooter without weaponmodel\n");
safe_remove(self);
}
precache_model(self.weaponmodel);
if (self.noise1) precache_sound(self.noise1);
if (self.noise2) precache_sound(self.noise2);
makevectors(self.angles);
self.movedir = v_forward;
if (self.delay) {
self.think = _trap_genericshooter_think;
self.nextthink = time + self.delay;
if (!self.wait)
self.wait = self.delay;
}
self.use = _trap_genericshooter_use;
};
/*QUAKED trap_spikeshooter (0 .5 .8) (-8 -8 -8) (8 8 8) superspike laser
When triggered, fires a spike in the direction set in QuakeEd.
Laser is only for REGISTERED.
*/
void() trap_spikeshooter = {
if (self.spawnflags & SPAWNFLAG_LASER) {
self.weaponmodel = "progs/laser.mdl";
self.noise1 = "enforcer/enfire.wav";
self.noise2 = "enforcer/enfstop.wav";
self.speed = 600;
self.dmg = 15;
self.items = EF_DIMLIGHT;
} else if (self.spawnflags & SPAWNFLAG_SUPERSPIKE) {
self.weaponmodel = "progs/s_spike.mdl";
self.noise1 = "weapons/spike2.wav";
self.noise2 = NULL_string;
self.speed = 1000;
self.dmg = 18;
} else {
self.weaponmodel = "progs/spike.mdl";
self.noise1 = "weapons/spike2.wav";
self.noise2 = NULL_string;
self.speed = 1000;
self.dmg = 9;
}
self.mass = self.dmg;
trap_genericshooter();
};
/*QUAKED trap_shooter (0 .5 .8) (-8 -8 -8) (8 8 8) superspike laser
Continuously fires spikes.
"wait" time between spike (1.0 default)
"nextthink" delay before firing first spike, so multiple shooters can be stagered.
*/
void() trap_shooter = {
if (!self.wait)
self.wait = 1;
self.speed = 500; // Beats me.
self.delay = self.nextthink + self.wait;
trap_spikeshooter();
};

View file

@ -0,0 +1,258 @@
#include "common.qh"
#include "mapents_util.qh"
#include "damage.qh"
#include "mapents_triggers.qh"
float(float d) _takedamage_use = {
if (time < self.attack_finished)
return FALSE;
self.attack_finished = time + self.wait;
self.health -= d;
if (self.health <= 0) {
self.health = self.max_health;
if (util_use_targets())
self.use();
}
deathmsg_nodisplay();
if (self.wait <= 0) {
self.solid = SOLID_NOT;
util_map_entity_cull();
}
return FALSE; /* Lie */
};
void() _trigger_generic_touch = {
local void() selfuse;
if (!is_living(other))
return;
if (time < self.attack_finished)
return;
self.attack_finished = time + self.wait;
selfuse = self.use;
self.use = NOTHING_function; /* Avoid endless loop */
if (util_use_targets())
selfuse();
self.use = selfuse;
if (self.wait <= 0) {
self.solid = SOLID_NOT;
util_map_entity_cull();
}
};
/*QUAKED trigger_generic (.5 .5 .5) NOTOUCH
Variable sized repeatable trigger. Must be targeted at one or more entities.
If "model" is set, the trigger will set it as its model.
If "health" is set, trigger must be killed to activate each time.
If "delay" is set, the trigger waits some time after activating before firing.
If "wait" is set, the trigger waits some time before able to trigger again.
If "count" is > 0, the trigger will only trigger count times.
If notouch is set, the trigger is only fired by other entities, not by touching or killing.
"noise1" is played at the trigger when triggered, if set.
"noise2" is played to the activator when triggered, if set.
"message" is displayed when triggered, if set.
*/
void() trigger_generic = {
/* Get mins/maxs */
setmodel(self, self.model);
/* Avoid displaying triggers */
self.model = "";
self.modelindex = 0;
if (self.health) {
self.max_health = self.health;
self.solid = SOLID_BBOX;
self.takedamage = DAMAGE_YES;
self.th_takedamage = _takedamage_use;
}
if (!self.solid) {
if (!(self.spawnflags & SPAWNFLAGS_TRIGGER_NOTOUCH)) {
self.solid = SOLID_TRIGGER;
self.touch = _trigger_generic_touch;
}
}
/* FIXME: This is a hackaround for qwsv */
if (self.origin == '0 0 0') {
self.origin = (self.mins + self.maxs) * 0.5;
self.mins = self.mins - self.origin;
self.maxs = self.maxs - self.origin;
setsize(self, self.mins, self.maxs);
setorigin(self, self.origin);
}
if (!self.use)
self.use = NOTHING_function;
util_map_entity_init();
util_map_entity_cull();
};
/*QUAKED info_teleport_destination (.5 .5 .5) (-8 -8 -8) (8 8 32)
This is the destination marker for a teleporter. It should have a "targetname"
field with the same value as a teleporter's "target" field.
*/
void() info_teleport_destination = {
self.origin = self.origin + '0 0 27';
info_notnull();
};
void() _trigger_teleport_touch = {
local entity spot;
local float spd;
if (!is_teleportable(other))
return;
spot = find(world, targetname, self.target);
if (!spot) {
damage(other, other, other, DAMAGE_MUSTDIE, NOTHING_function);
return;
}
effect_teleport_fog(other.origin);
teleport(other, spot);
spd = vlen(other.velocity);
makevectors(other.angles);
other.velocity = v_forward * spd;
};
#define SPAWNFLAGS_SILENT 2
/*QUAKED trigger_teleport (.5 .5 .5) ? PLAYER_ONLY SILENT
Any object touching this will be transported to the corresponding
info_teleport_destination entity. You must set the "target" field,
and create an object with a "targetname" field that matches.
If the trigger_teleport has a targetname, it will only teleport
entities when it has been fired.
*/
void() trigger_teleport = {
if (!(self.spawnflags & SPAWNFLAGS_SILENT) && !self.noise)
self.noise = "ambience/hum1.wav";
setmodel(self, self.model);
self.model = NULL_string;
self.modelindex = 0;
util_map_entity_init();
self.solid = SOLID_TRIGGER;
self.touch = _trigger_teleport_touch;
self.use = _trigger_teleport_touch;
};
void() _trigger_hurt_deathmsg = {
bprint(PRINT_DEATH, name(self), " was in the wrong place.\n");
};
void() _trigger_hurt_use = {
damage(other, self, self, self.dmg, _trigger_hurt_deathmsg);
};
/*QUAKED trigger_hurt (.5 .5 .5) ?
Any object touching this will be hurt
set dmg to damage amount
*/
void() trigger_hurt = {
if (!self.wait) self.wait = 1;
trigger_generic();
self.use = _trigger_hurt_use;
};
#define SPAWNFLAGS_PUSH_ONCE 1
#define SPAWNFLAGS_PUSH_ADD 2
void() _trigger_push_use = {
if (!is_solid(other))
return;
if (!util_use_targets())
return;
if (self.spawnflags & SPAWNFLAGS_PUSH_ADD)
other.velocity = other.velocity + self.movedir;
else
other.velocity = self.movedir;
if (!is_living(other))
return;
if (self.noise3)
sound(other, CHAN_AUTO, self.noise3, 1, ATTN_NORM);
};
/*QUAKED trigger_push (.5 .5 .5) ? PUSH_ADD PUSH_ONCE
Pushes the player
*/
void() trigger_push = {
if (!self.wait) self.wait = 1;
if (!self.speed) self.speed = 1000;
if (!self.noise1 && !self.noise2 && !self.noise3)
self.noise3 = "ambience/windfly.wav";
if (self.noise3) precache_sound(self.noise3);
if (self.spawnflags & SPAWNFLAGS_PUSH_ONCE)
self.count = 1;
trigger_generic();
util_set_movedir();
self.movedir = self.movedir * self.speed * 10;
self.use = _trigger_push_use;
};
#define SPAWNFLAGS_NO_INTERMISSION 1
void() _trigger_changelevel_do = {
local string nextmap;
nextmap = self.map;
if (!self.map) nextmap = "start.bsp";
changelevel(nextmap);
};
void() _trigger_changelevel_use = {
if (!is_living(other) || !is_cl(other))
return;
// Bleah.
self.touch = NOTHING_function;
self.think = _trigger_changelevel_do;
self.nextthink = time;
};
/*QUAKED trigger_changelevel (.5 .5 .5) ? NO_INTERMISSION
When a player touches this, the level changes. The level
will change to the map set in the map variable. If it is
not set, the map will change to a random level in the list.
If NO_INTERMISSION is set, the view will not go to an
info_intermission spot and display stats in co-op games.
*/
void() trigger_changelevel = {
trigger_generic();
self.use = _trigger_changelevel_use;
};

View file

@ -0,0 +1,7 @@
#ifndef MAPENTS_TRIGGERS_qh
#define MAPENTS_TRIGGERS_qh 1
#define SPAWNFLAGS_TRIGGER_NOTOUCH 2
void() trigger_generic;
#endif

View file

@ -0,0 +1,182 @@
#include "common.qh"
#include "misc.qh"
#include "mapents_util.qh"
void() util_map_entity_init = {
self.deadflag = DEAD_NONLIVING;
if (self.noise && sv_spawning) {
if (!self.volume) self.volume = 0.5;
if (!self.attenuation) self.attenuation = ATTN_STATIC;
precache_sound(self.noise);
ambientsound(center(self), self.noise, self.volume, self.attenuation);
} else {
if (!self.volume) self.volume = 1.0;
if (!self.attenuation) self.attenuation = ATTN_NORM;
}
if (sv_spawning) {
if (self.noise1) precache_sound(self.noise1);
if (self.noise2) precache_sound(self.noise2);
if (self.noise5) precache_sound(self.noise5);
if (self.noise6) precache_sound(self.noise6);
}
if (self.mangle)
self.angles = self.mangle;
if (self.model) {
if (sv_spawning)
precache_model(self.model);
setmodel(self, self.model);
}
setsize(self, self.mins, self.maxs);
setorigin(self, self.origin); // Links BSP models
};
void() util_map_entity_cull = {
if (self.solid || self.takedamage)
return;
if (self.nextthink > time)
return;
if (!sv_spawning) {
if (self.targetname) {
if (find(world, target, self.targetname))
return;
}
if (self.target) {
local entity oldself;
oldself = self;
self = world;
while (self = find(self, targetname, self.target)) {
if (self == oldself)
continue;
util_map_entity_cull();
}
self = oldself;
}
} else {
if (self.targetname || self.target) {
self.think = util_map_entity_cull;
self.nextthink = time + sv_mintic;
return;
}
}
if (self.model) safe_makestatic(self);
else safe_remove(self);
};
void() util_map_entity_drop = {
self.origin = self.origin + '0 0 2';
if (!droptofloor()) {
dprint(self.classname, " fell out of level from ", vtos(self.origin), "\n");
remove(self);
return;
}
};
float() util_check_targets = {
/*
if (self.spawnflags & (SPAWNFLAGS_CHECK_ITEMS|SPAWNFLAGS_TAKE_ITEMS)) {
}
*/
return TRUE;
};
float() util_use_targets = {
if (!util_check_targets())
return FALSE;
if (self.noise1)
sound(self, CHAN_VOICE, self.noise1, self.volume, self.attenuation);
if (self.noise2)
sound(other, CHAN_ITEM, self.noise2, self.volume, self.attenuation);
if (self.message && is_cl(other))
centerprint(other, self.message);
if (self.th_activate)
self.th_activate();
if (self.target)
foreach_field(targetname, self.target, use);
if (self.killtarget)
foreach(targetname, self.killtarget, safe_remove);
if (self.count > 0) {
self.count--;
if (!self.count) {
self.targetname = NULL_string;
self.target = NULL_string;
self.killtarget = NULL_string;
self.use = NOTHING_function;
self.touch = NOTHING_function;
util_map_entity_cull();
}
}
return TRUE;
};
float(entity e) is_living = {
return (e.deadflag == DEAD_NO) && is_solid(e);
};
float(entity e) is_solid = {
return (e.solid != SOLID_NOT && e.solid != SOLID_TRIGGER);
};
float(entity e) is_teleportable = {
return e.movetype != MOVETYPE_NONE &&
e.movetype != MOVETYPE_PUSH &&
e.movetype != MOVETYPE_NOCLIP &&
(e.solid == SOLID_BBOX || e.solid == SOLID_SLIDEBOX);
};
void() util_set_movedir = {
if (self.mangle != '0 0 0')
self.angles = self.mangle;
if (self.angles == '0 -1 0')
self.movedir = '0 0 1';
else if (self.angles == '0 -2 0')
self.movedir = '0 0 -1';
else {
makevectors(self.angles);
self.movedir = v_forward;
}
self.angles = '0 0 0';
};
float(entity ent1, entity ent2) util_entities_touch = {
if (ent1.mins_x > ent2.maxs_x)
return FALSE;
if (ent1.mins_y > ent2.maxs_y)
return FALSE;
if (ent1.mins_z > ent2.maxs_z)
return FALSE;
if (ent2.mins_x > ent1.maxs_x)
return FALSE;
if (ent2.mins_y > ent1.maxs_y)
return FALSE;
if (ent2.mins_z > ent1.maxs_z)
return FALSE;
return TRUE;
};

View file

@ -0,0 +1,24 @@
#ifndef MAPENTS_UTIL_qh
#define MAPENTS_UTIL_qh 1
#define SPAWNFLAGS_CHECK_ITEMS 16384
#define SPAWNFLAGS_TAKE_ITEMS 32768
.void() th_activate;
void() util_map_entity_init;
void() util_map_entity_cull;
void() util_map_entity_drop;
void() util_set_movedir;
float() util_check_targets;
float() util_use_targets;
float(entity e) is_living;
float(entity e) is_solid;
float(entity e) is_teleportable;
float(entity ent1, entity ent2) util_entities_touch;
#endif

20
klik/math.qc Normal file
View file

@ -0,0 +1,20 @@
#include "math.qh"
/* Ugh. QuakeC doesn't include these ops. */
float(float num, float bits) shl = {
if (bits >= 16) { num *= 65536; bits -= 16; }
if (bits >= 8) { num *= 256; bits -= 8; }
if (bits >= 4) { num *= 16; bits -= 4; }
if (bits >= 2) { num *= 4; bits -= 2; }
if (bits >= 1) { num *= 2; }
return num;
};
float(float num, float bits) shr = {
if (bits >= 16) { num /= 65536; bits -= 16; }
if (bits >= 8) { num /= 256; bits -= 8; }
if (bits >= 4) { num /= 16; bits -= 4; }
if (bits >= 2) { num /= 4; bits -= 2; }
if (bits >= 1) { num /= 2; }
return floor(num);
};

14
klik/math.qh Normal file
View file

@ -0,0 +1,14 @@
#ifndef MATH_qh
#define MATH_qh 1
@extern {
float(float num, float bits) shl;
float(float num, float bits) shr;
#define min(a, b) ((a)>(b)?(b):(a))
#define max(a, b) ((a)>(b)?(a):(b))
};
#endif

25
klik/mdl/mdl.qc Normal file
View file

@ -0,0 +1,25 @@
#include "common.qh"
#include "bodyque.qh"
#include "mdl.qh"
void() _mdl_bodyque_think = {
if (!self.mdl_thought) self.mdl_think();
self.mdl_thought = FALSE;
self.nextthink = time + 0.1;
};
entity(float func, float extra) mdl_bodyque_and_func = {
local entity stemp, ret;
stemp = self;
ret = self = bodyque_que(self);
if (self.mdl_func)
self.mdl_func(func, extra);
self = stemp;
return ret;
};
void(float func, float extra) mdl_func_void = {};

36
klik/mdl/mdl.qh Normal file
View file

@ -0,0 +1,36 @@
#ifndef MDL_qh
#define MDL_qh 1
.void(float func, float extra) mdl_func;
.float mdl_mod;
.void() mdl_think;
.float mdl_thought;
.float mdl_var;
#define MDL_FUNC_IDLE 0
#define MDL_FUNC_JUMP 1
#define MDL_FUNC_PAIN 2
#define MDL_FUNC_FIRE 3
#define MDL_FUNC_DIE 4
#define MDL_FUNC_GIB 5
#define MDL_MOD_WEP_MASK 255
#define MDL_MOD_WEP_AXE 1
#define MDL_MOD_WEP_SHOTGUN 2
#define MDL_MOD_WEP_SUPER_SHOTGUN 3
#define MDL_MOD_WEP_NAILGUN 4
#define MDL_MOD_WEP_SUPER_NAILGUN 5
#define MDL_MOD_WEP_GRENADE_LAUNCHER 6
#define MDL_MOD_WEP_ROCKET_LAUNCHER 7
#define MDL_MOD_WEP_LIGHTNING_GUN 8
#define MDL_MOD_SWIM_OVER 256
#define MDL_MOD_SWIM_IN 512
#define MDL_MOD_SWIM (MDL_MOD_SWIM_IN|MDL_MOD_SWIM_OVER)
void(float func, float extra) mdl_func_void;
entity(float func, float extra) mdl_bodyque_and_func;
#endif

18
klik/mdl/mdl_eyes.qc Normal file
View file

@ -0,0 +1,18 @@
#include "common.qh"
#include "mdl.qh"
#include "mdl_eyes.qh"
void() mdl_setup_eyes = {
setmodel(self, "progs/eyes.mdl");
setsize(self, VEC_HULL_MIN, VEC_HULL_MAX);
self.view_ofs = '0 0 22';
self.mdl_func = mdl_func_void;
self.mdl_think = NOTHING_function;
};
void() mdl_eyes_init = {
precache_model("progs/eyes.mdl");
};

7
klik/mdl/mdl_eyes.qh Normal file
View file

@ -0,0 +1,7 @@
#ifndef MDL_EYES_qh
#define MDL_EYES_qh 1
void() mdl_eyes_init;
void() mdl_setup_eyes;
#endif

396
klik/mdl/mdl_player.qc Normal file
View file

@ -0,0 +1,396 @@
#include "common.qh"
#include "mdl.qh"
#include "mdl_player.qh"
// running
$frame axrun1 axrun2 axrun3 axrun4 axrun5 axrun6
$frame rockrun1 rockrun2 rockrun3 rockrun4 rockrun5 rockrun6
// standing
$frame stand1 stand2 stand3 stand4 stand5
$frame axstnd1 axstnd2 axstnd3 axstnd4 axstnd5 axstnd6
$frame axstnd7 axstnd8 axstnd9 axstnd10 axstnd11 axstnd12
// pain
$frame axpain1 axpain2 axpain3 axpain4 axpain5 axpain6
$frame pain1 pain2 pain3 pain4 pain5 pain6
// death
$frame axdeth1 axdeth2 axdeth3 axdeth4 axdeth5 axdeth6
$frame axdeth7 axdeth8 axdeth9
$frame deatha1 deatha2 deatha3 deatha4 deatha5 deatha6 deatha7 deatha8
$frame deatha9 deatha10 deatha11
$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8
$frame deathb9
$frame deathc1 deathc2 deathc3 deathc4 deathc5 deathc6 deathc7 deathc8
$frame deathc9 deathc10 deathc11 deathc12 deathc13 deathc14 deathc15
$frame deathd1 deathd2 deathd3 deathd4 deathd5 deathd6 deathd7
$frame deathd8 deathd9
$frame deathe1 deathe2 deathe3 deathe4 deathe5 deathe6 deathe7
$frame deathe8 deathe9
// attacks
$frame nailatt1 nailatt2
$frame light1 light2
$frame rockatt1 rockatt2 rockatt3 rockatt4 rockatt5 rockatt6
$frame shotatt1 shotatt2 shotatt3 shotatt4 shotatt5 shotatt6
$frame axatt1 axatt2 axatt3 axatt4 axatt5 axatt6
$frame axattb1 axattb2 axattb3 axattb4 axattb5 axattb6
$frame axattc1 axattc2 axattc3 axattc4 axattc5 axattc6
$frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
void() _mdl_player_axe_walk = {
self.frame++;
if (self.frame < $axrun1 || self.frame > $axrun6)
self.frame = $axrun1;
};
void() _mdl_player_gun_walk = {
self.frame++;
if (self.frame < $rockrun1 || self.frame > $rockrun6)
self.frame = $rockrun1;
};
void() _mdl_player_axe_idle = {
self.frame++;
if (self.frame < $axstnd1 || self.frame > $axstnd12)
self.frame = $axstnd1;
};
void() _mdl_player_gun_idle = {
self.frame++;
if (self.frame < $stand1 || self.frame > $stand5)
self.frame = $stand1;
};
void() mdl_player_idle =
{
self.mdl_think = mdl_player_idle;
if ((self.flags & FL_ONGROUND) && (self.velocity_x || self.velocity_y)) {
if ((self.mdl_mod&MDL_MOD_WEP_MASK) == MDL_MOD_WEP_AXE)
_mdl_player_axe_walk();
else _mdl_player_gun_walk();
} else {
if ((self.mdl_mod&MDL_MOD_WEP_MASK) == MDL_MOD_WEP_AXE)
_mdl_player_axe_idle();
else _mdl_player_gun_idle();
}
self.mdl_thought = TRUE;
};
void() _mdl_player_axe_pain = {
self.frame++;
if (self.frame < $axpain1 || self.frame > $axpain6)
mdl_player_idle();
};
void() _mdl_player_gun_pain = {
self.frame++;
if (self.frame < $pain1 || self.frame > $pain6)
mdl_player_idle();
};
void(float d) mdl_player_pain = {
local vector impact_dir;
if (time < self.mdl_var)
return;
self.mdl_var = time + 0.2;
impact_dir = '0 0 0' - self.dmg_inflictor.velocity;
impact_dir = normalize(impact_dir);
effect_blood(self.origin, impact_dir, d);
if (self.mdl_think != mdl_player_idle)
return;
if ((self.mdl_mod&MDL_MOD_WEP_MASK) == MDL_MOD_WEP_AXE) {
self.frame = $axpain1;
self.mdl_think = _mdl_player_axe_pain;
} else {
self.frame = $pain1;
self.mdl_think = _mdl_player_gun_pain;
}
self.mdl_thought = TRUE;
};
void() _mdl_player_death = {
self.frame++;
if (self.frame >= self.count) {
self.mdl_think = NOTHING_function;
return;
}
};
void(float type) mdl_player_die = {
self.angles_x = 0;
self.angles_z = 0;
self.avelocity_x = 0;
self.avelocity_z = 0;
if ((self.mdl_mod&MDL_MOD_WEP_MASK) == MDL_MOD_WEP_AXE) {
self.frame = $axdeth1; self.count = $axdeth9;
setsize(self, VEC_HULL_MIN, '16 16 0');
} else {
if (type == 0) {
self.frame = $deatha1; self.count = $deatha11;
setsize(self, VEC_HULL_MIN, '16 16 -12');
} else if (type == 1) {
self.frame = $deathb1; self.count = $deathb9;
setsize(self, VEC_HULL_MIN, '16 16 0');
} else if (type == 2) {
self.frame = $deathc1; self.count = $deathc15;
setsize(self, VEC_HULL_MIN, '16 16 -12');
} else if (type == 3) {
self.frame = $deathd1; self.count = $deathd9;
setsize(self, VEC_HULL_MIN, '16 16 -12');
} else {
self.frame = $deathe1; self.count = $deathe9;
setsize(self, VEC_HULL_MIN, '16 16 18');
}
}
self.mdl_think = _mdl_player_death;
self.mdl_thought = TRUE;
};
/* Rocket, grenade launcher, etc */
void() _mdl_player_fire = {
self.frame++;
if (self.frame < $rockatt1 || self.frame > $rockatt6)
mdl_player_idle();
};
void() mdl_player_fire = {
self.frame = $rockatt1;
self.mdl_think = _mdl_player_fire;
effect_muzzleflash();
self.mdl_thought = TRUE;
};
/* shotgun, super shotgun. */
void() _mdl_player_fire_shotgun = {
self.frame++;
if (self.frame < $shotatt1 || self.frame > $shotatt6)
mdl_player_idle();
};
void() mdl_player_fire_shotgun = {
self.frame = $shotatt1;
self.mdl_think = _mdl_player_fire_shotgun;
effect_muzzleflash();
self.mdl_thought = TRUE;
};
/* lightning gun */
void() _mdl_player_fire_lightning = {
self.frame++;
if (self.frame < $light1 || self.frame > $light2)
self.frame = $light1;
effect_muzzleflash();
};
void() mdl_player_fire_lightning = {
self.frame = $light1;
self.mdl_think = _mdl_player_fire_lightning;
effect_muzzleflash();
self.mdl_thought = TRUE;
};
/* nailgun, super nailgun */
void() _mdl_player_fire_nail = {
self.frame++;
if (self.frame < $nailatt1 || self.frame > $nailatt2)
self.frame = $nailatt1;
};
void() mdl_player_fire_nail = {
self.frame = $nailatt2;
self.mdl_think = _mdl_player_fire_nail;
self.mdl_think();
effect_muzzleflash();
self.mdl_thought = TRUE;
};
/* Axe */
void() _mdl_player_fire_axe_a = {
self.frame++;
if (self.frame < $axatt1 || self.frame > $axatt4)
mdl_player_idle();
};
void() _mdl_player_fire_axe_b = {
self.frame++;
if (self.frame < $axattb1 || self.frame > $axattb4)
mdl_player_idle();
};
void() _mdl_player_fire_axe_c = {
self.frame++;
if (self.frame < $axattc1 || self.frame > $axattc4)
mdl_player_idle();
};
void() _mdl_player_fire_axe_d = {
self.frame++;
if (self.frame < $axattd1 || self.frame > $axattd4)
mdl_player_idle();
};
void() mdl_player_fire_axe = {
local float r;
r = random();
if (r < 0.25) {
self.frame = $axatt1;
self.mdl_think = _mdl_player_fire_axe_a;
} else if (r < 0.5) {
self.frame = $axattb1;
self.mdl_think = _mdl_player_fire_axe_b;
} else if (r < 0.75) {
self.frame = $axattc1;
self.mdl_think = _mdl_player_fire_axe_c;
} else {
self.frame = $axattd1;
self.mdl_think = _mdl_player_fire_axe_d;
}
self.mdl_think();
self.mdl_thought = 1;
};
/* :) */
void() mdl_player_gib = {
local entity gib;
local float r, gibs, velmag;
local vector vel, giborg;
velmag = vlen(self.velocity);
if (velmag == 0)
vel = '0 0 1';
else vel = self.velocity * (1/velmag);
if (velmag < 200) velmag = 200;
if (vel == '0 0 0')
vel = '0 0 1';
self.mass /= 6;
gibs = 5 + crandom()*1;
giborg = center(self);
while (gibs-- > 0) {
gib = spawn("PLAYER_GIB");
gib.solid = SOLID_NOT;
gib.movetype = MOVETYPE_BOUNCE;
gib.mass = self.mass;
gib.avelocity_x = crandom()*300;
gib.avelocity_y = crandom()*300;
gib.avelocity_z = crandom()*300;
gib.velocity_x = vel_x + crandom()*0.2;
gib.velocity_y = vel_y + crandom()*0.2;
gib.velocity_z = vel_z + crandom()*0.2;
gib.velocity = normalize(gib.velocity) * velmag;
r = random()*3;
if (r < 1) gib.model = "progs/gib1.mdl";
else if (r < 2) gib.model = "progs/gib2.mdl";
else gib.model = "progs/gib3.mdl";
setsize(gib, '0 0 0', '0 0 0');
setmodel(gib, gib.model);
setorigin(gib, giborg);
gib.think = SUB_remove;
gib.nextthink = time + 5 + random()*10;
}
self.avelocity = '0 0 0';
self.angles_x = random()*360;
self.angles_y = random()*360;
self.angles_z = random()*360;
self.velocity_x = vel_x + crandom()*0.1;
self.velocity_y = vel_y + crandom()*0.1;
self.velocity_z = vel_z + crandom()*0.1;
self.velocity = normalize(self.velocity) * velmag;
setsize(self, '0 0 0', '0 0 0');
setmodel(self, "progs/h_player.mdl");
setorigin(self, self.origin + self.view_ofs);
self.view_ofs = '0 0 0';
self.mdl_think = NOTHING_function;
self.mdl_func = mdl_func_void;
};
void() mdl_player_init = {
precache_model("progs/player.mdl");
precache_model("progs/h_player.mdl");
precache_model("progs/gib1.mdl");
precache_model("progs/gib2.mdl");
precache_model("progs/gib3.mdl");
};
void(float func, float extra) mdl_func_player = {
if (func == MDL_FUNC_IDLE) mdl_player_idle();
else if (func == MDL_FUNC_JUMP) { extra = 0; }
else if (func == MDL_FUNC_PAIN) mdl_player_pain(extra);
else if (func == MDL_FUNC_FIRE) {
local float wmod;
wmod = self.mdl_mod & MDL_MOD_WEP_MASK;
if (wmod == MDL_MOD_WEP_AXE) mdl_player_fire_axe();
else if (wmod == MDL_MOD_WEP_SHOTGUN) mdl_player_fire_shotgun();
else if (wmod == MDL_MOD_WEP_SUPER_SHOTGUN) mdl_player_fire_shotgun();
else if (wmod == MDL_MOD_WEP_NAILGUN) mdl_player_fire_nail();
else if (wmod == MDL_MOD_WEP_SUPER_NAILGUN) mdl_player_fire_nail();
else if (wmod == MDL_MOD_WEP_GRENADE_LAUNCHER) mdl_player_fire();
else if (wmod == MDL_MOD_WEP_ROCKET_LAUNCHER) mdl_player_fire();
else if (wmod == MDL_MOD_WEP_LIGHTNING_GUN) mdl_player_fire_lightning();
else mdl_player_fire();
}
else if (func == MDL_FUNC_DIE) mdl_player_die(extra);
else if (func == MDL_FUNC_GIB) mdl_player_gib();
else mdl_player_idle();
};
void() mdl_setup_player = {
self.model = "progs/player.mdl";
setmodel(self, self.model);
setsize(self, VEC_HULL_MIN, VEC_HULL_MAX);
self.view_ofs = '0 0 22';
self.mdl_func = mdl_func_player;
self.mdl_func(MDL_FUNC_IDLE, 0);
self.mdl_var = 0;
};

7
klik/mdl/mdl_player.qh Normal file
View file

@ -0,0 +1,7 @@
#ifndef MDL_PLAYER_qh
#define MDL_PLAYER_qh 1
void() mdl_player_init;
void() mdl_setup_player;
#endif

13
klik/mdl/mdl_void.qc Normal file
View file

@ -0,0 +1,13 @@
#include "common.qh"
#include "mdl.qh"
#include "mdl_void.qh"
void() mdl_setup_void = {
self.modelindex = 0; /* Don't use setmodel */
setsize(self, '0 0 0', '0 0 0');
self.view_ofs = '0 0 0';
self.mdl_func = mdl_func_void;
self.mdl_think = NOTHING_function;
};

6
klik/mdl/mdl_void.qh Normal file
View file

@ -0,0 +1,6 @@
#ifndef MDL_VOID_qh
#define MDL_VOID_qh 1
void() mdl_setup_void;
#endif

17
klik/menu.qc Normal file
View file

@ -0,0 +1,17 @@
#include "common.qh"
#include "menu.qh"
void(void() menu_func) menu_set = {
self.menu_state = 0;
self.menu_time = 0;
self.menu_think = menu_func;
};
float() util_menu_needs_print = {
if (time > self.menu_time) {
self.menu_time = time + 1.4;
return TRUE;
}
return FALSE;
};

13
klik/menu.qh Normal file
View file

@ -0,0 +1,13 @@
#ifndef MENU_qh
#define MENU_qh 1
#include "menus.qh"
.float menu_state;
.float menu_time;
.void() menu_think;
void(void() menu_func) menu_set;
float() util_menu_needs_print;
#endif

53
klik/menus.qc Normal file
View file

@ -0,0 +1,53 @@
#include "common.qh"
#include "menu.qh"
/*
void() menu_team = {
if (team_ischosen(self))
menu_set(menu_equip);
if (util_menu_needs_print() && is_cl(self)) {
centerprint(self,
"Team\n"
"\<\-\-\-\-\>\n"
"1\b.\b Red\n"
"2\b.\b Blue\n"
"\n"
"0\b.\b Auto\n"
);
}
if (self.impulse == 1) {
team_join(TEAM_RED);
} else if (self.impulse == 2) {
team_join(TEAM_BLUE);
} else if (self.impulse == 10 || self.button0 || self.button1 || self.button2) {
team_join_auto();
}
self.impulse = 0;
self.button0 = self.button1 = self.button2 = 0;
};
*/
void() menu_intro = {
if (!self.menu_state)
self.menu_state = time + 3;
else if (time >= self.menu_state) {
if (is_cl(self))
centerprint(self, "");
PutClientInGame();
return;
}
if (util_menu_needs_print()) {
if (is_cl(self))
centerprint(self,
"\[ This server is running Klik 0.0.7 \]\n"
"\[ by Zinx Verituse \]\n"
"\[ http://staff.xmms.org/zinx/klik \]\n"
"\n"
"\<[ It's a Quake World. ]\>\n"
);
}
};

6
klik/menus.qh Normal file
View file

@ -0,0 +1,6 @@
#ifndef MENUS_qh
#define MENUS_qh 1
void() menu_intro;
#endif

402
klik/misc.qc Normal file
View file

@ -0,0 +1,402 @@
#include "common.qh"
#include "protocol.qh"
#include "misc.qh"
#include "teleport.qh"
// ===================================================================== //
entity(string clname) spawn = {
local entity e;
e = BUILTIN_spawn();
e.classname = clname;
return e;
};
// ===================================================================== //
void() SUB_remove = { remove(self); };
void(entity e) safe_remove = {
e.takedamage = DAMAGE_NO;
e.solid = SOLID_NOT;
e.model = NULL_string;
e.modelindex = 0;
e.think = SUB_remove;
e.nextthink = time;
};
// ===================================================================== //
void() SUB_makestatic = { makestatic(self); };
void(entity e) safe_makestatic = {
if (sv_spawning) {
makestatic(self);
return;
}
e.takedamage = DAMAGE_NO;
e.solid = SOLID_NOT;
e.think = SUB_makestatic;
e.nextthink = time;
};
// ===================================================================== //
void() _sound_vector_think = {
sound(self, CHAN_VOICE, self.noise1, self.volume, self.attenuation);
remove(self);
};
void(vector org, string samp, float vol, float atten) sound_vector = {
local entity e;
e = spawn("SOUND");
e.origin = org;
e.noise1 = samp;
e.volume = vol;
e.attenuation = atten;
e.think = _sound_vector_think;
e.nextthink = time;
};
// ===================================================================== //
float(vector org) _missile_th_teleport = {
self.owner = world;
return TRUE;
};
void(entity mis) missile_check_teleport;
void() _missile_always_trigger = {
self.think = SUB_remove;
self.nextthink = self.attack_finished;
if (self.movetype != MOVETYPE_FLYMISSILE && self.movetype != MOVETYPE_FLY)
return;
tl_proj_begin();
/* Make sure we're still going to hit the thing */
traceline(self.origin, self.origin + self.velocity * sv_maxtic*2, FALSE, self);
if (trace_ent == self.enemy) tl_touch(trace_ent, self);
else self.enemy = world;
tl_proj_end();
missile_check_teleport(self);
};
void(entity mis) missile_check_teleport = {
local float duration;
tl_proj_begin();
trace_ent = mis;
trace_endpos = mis.origin;
duration = mis.attack_finished - time;
while (duration > sv_maxtic) {
traceline(trace_endpos, trace_endpos + mis.velocity*duration, FALSE, trace_ent);
if (!trace_ent || trace_ent.solid == SOLID_BSP) {
/* Don't bother tracing through BSP, it won't happen. */
break;
}
if (tl_issolid(trace_ent) || mis.enemy == trace_ent || (duration*trace_fraction) <= sv_maxtic) {
/* We hit a triggered trigger,
a solid ent, or something we _just_ hit */
if (trace_fraction == 0) {
/* We're not going anywhere. Fudge it. */
break;
}
/* Trace on past it. */
duration -= duration*trace_fraction;
continue;
}
/* Reached a [new] trigger */
mis.enemy = trace_ent;
mis.think = _missile_always_trigger;
mis.nextthink = time + duration*trace_fraction - sv_maxtic;
break;
}
tl_proj_end();
};
entity(string clname, string mod, vector org, vector dir, float spd) spawn_missile = {
newmis = spawn(clname);
newmis.owner = self;
newmis.goalentity = self;
newmis.movetype = MOVETYPE_FLYMISSILE;
newmis.solid = SOLID_BBOX;
newmis.deadflag = DEAD_NONLIVING;
newmis.th_teleport = _missile_th_teleport;
setmodel(newmis, mod);
setsize(newmis, '0 0 0', '0 0 0');
setorigin(newmis, org);
newmis.angles = vectoangles(dir);
newmis.speed = spd;
newmis.velocity = dir * spd;
newmis.attack_finished = time + (6000 / spd);
newmis.think = SUB_remove;
newmis.nextthink = newmis.attack_finished;
missile_check_teleport(newmis);
return newmis;
};
// ===================================================================== //
entity tl_first;
.entity tl_next;
void() tl_proj_begin = {
local entity walk;
tl_first = world;
for (walk = nextent(world); walk; walk = nextent(walk)) {
if (walk.solid != SOLID_TRIGGER)
continue;
walk.tl_next = tl_first;
tl_first = walk;
walk.solid = SOLID_BBOX;
walk.tl_notsolid = TRUE;
setorigin(walk, walk.origin); // relink
}
};
void() tl_proj_end = {
local entity walk;
for (walk = tl_first; walk; walk = walk.tl_next) {
walk.solid = SOLID_TRIGGER;
walk.tl_notsolid = FALSE;
setorigin(walk, walk.origin); // relink
}
};
void(entity trigger, entity fake_proj) tl_touch = {
local entity oldself, oldother;
if (!trigger.touch)
return;
tl_proj_end();
oldself = self;
oldother = other;
self = trigger;
other = fake_proj;
self.touch();
self = oldself;
other = oldother;
tl_proj_begin();
};
// ===================================================================== //
string(entity e) name = {
if (e.netname) return e.netname;
if (e.classname) return e.classname;
if (e.velocity)
return "an unidentified flying object";
return "an unidentified stationary object";
};
// ===================================================================== //
void(.string fld, string match, void(entity e) func) foreach = {
local entity ent;
ent = world;
while ((ent = find(ent, fld, match))) {
if (!func) {
dprint("NULL function in foreach, classname: ", ent.classname, "\n");
continue;
}
func(ent);
}
};
void(.string fld, string match, .void() func) foreach_field = {
local entity oldself;
oldself = self;
self = world;
while ((self = find(self, fld, match))) {
if (!self.func) {
dprint("NULL function in foreach_field, classname: ", self.classname, "\n");
continue;
}
self.func();
}
self = oldself;
};
// ===================================================================== //
float(entity newself, entity newother, float() func) switcheroo = {
local entity oldself, oldother;
local float ret;
oldself = self;
oldother = other;
self = newself;
other = newother;
ret = func();
self = oldself;
other = oldother;
return ret;
};
// ===================================================================== //
float(float current, float increment, float max) increase_bound = {
local float diff;
diff = max - current;
if (diff <= 0) return current;
if (diff > increment) diff = increment;
return current + diff;
};
float(.float fld, float increment, float max) increase_field = {
local float new;
new = increase_bound(self.fld, increment, max);
if (new == self.fld)
return FALSE;
self.fld = new;
return TRUE;
};
// ===================================================================== //
/* Not to be confused with maxspeed */
float(entity e) calc_max_speed = {
local float spd;
spd = e.maxspeed;
if (self.waterlevel >= 2)
spd = spd * 0.7; // Bah. Hard coded in engine.
else if (!self.waterlevel && !(self.flags & FL_ONGROUND)) {
if (spd > 30)
spd = 30; // Also hard coded.
}
return spd;
};
// ===================================================================== //
entity _xprint_client;
float _xprint_level;
void(entity client, float level) xprint_start = {
_xprint_client = client;
_xprint_level = level;
};
void(string str) xprint_str = {
msg_entity = _xprint_client;
WriteByte(MSG_ONE, SVC_PRINT);
WriteByte(MSG_ONE, _xprint_level);
WriteString(MSG_ONE, str);
};
// ===================================================================== //
entity(.string fld, string str) find_random = {
local float r, numents;
local entity ent;
numents = 0;
r = floor(random() * 512);
while (1) {
ent = find(world, fld, str);
if (!ent) return world;
while (ent) {
numents++;
r--;
if (r <= 0) return ent;
ent = find(ent, fld, str);
}
r -= numents * floor(r / numents);
}
return world;
};
// ===================================================================== //
entity(entity ech) random_enemy_chain = {
local entity walk;
local float tot, r;
r = floor(random()*64) + 1;
tot = 1;
for (walk = ech.enemy; walk != ech; walk = walk.enemy) {
r--;
if (r <= 0)
return walk;
tot++;
}
if (!tot)
return ech;
/* Ok, only look at half the remaining ones */
tot = floor(tot * 0.5);
if (!tot)
return ech.enemy;
r -= tot * floor(r / tot);
for (walk = ech.enemy; walk; walk = walk.enemy) {
if (r <= 0)
return walk;
r--;
}
return world;
};
// ===================================================================== //

73
klik/misc.qh Normal file
View file

@ -0,0 +1,73 @@
#ifndef MISC_qh
#define MISC_qh 1
/* Random miscellaneous functions */
@extern {
entity(string clname) spawn;
string(entity e) name; /* Returns the pretty entity name */
#define crandom() (2.0*(random() - 0.5))
void(entity e) makestatic;
void(vector pos, string samp, float vol, float atten) ambientsound;
void() SUB_remove;
void(entity e) safe_remove;
void() SUB_makestatic;
void(entity e) safe_makestatic;
void(vector org, string samp, float vol, float atten) sound_vector;
entity(string clname, string mod, vector org, vector dir, float speed) spawn_missile;
/* :) */
void(.string fld, string match, void(entity e) func) foreach;
void(.string fld, string match, .void() func) foreach_field;
/* swaps self/other temporarily */
float(entity newself, entity newother, float() func) switcheroo;
/* Returns new value */
float(float current, float increment, float max) increase_bound;
/* Returns FALSE if not increased */
float(.float fld, float increment, float max) increase_field;
/* Calculate the player's current maximum speed, taking water/air in to account */
float(entity e) calc_max_speed;
/* sprint one string at a time, and get them all to the destination */
void(entity client, float level) xprint_start;
void(string str) xprint_str;
#define is_activeplayer(e) (e.flags & FL_CLIENT)
#define is_cl(e) (e.flags & FL_CLIENT)
#define is_autothink(e) (e.flags & FL_AUTOTHINK)
/* Return a random entity that matches, or world */
entity(.string fld, string str) find_random;
/* Return something from the .enemy chain */
entity(entity ech) random_enemy_chain;
#define vieworigin(e) (e.origin + e.view_ofs)
#define center(e) ((e.absmin + e.absmax) * 0.5)
/* FIXME: Make this an mdl func? */
#define shootorigin(e) (vieworigin(e) - '0 0 6')
/* Stuff for traceline "projectiles" to hit triggers like normal projectiles */
void() tl_proj_begin;
void() tl_proj_end;
void(entity trigger, entity fake_proj) tl_touch;
.float tl_notsolid;
#define tl_issolid(ent) (!ent.tl_notsolid)
};
#endif

176
klik/override.qc Normal file
View file

@ -0,0 +1,176 @@
#include "common.qh"
#include "items.qh"
#include "damage.qh"
#include "teleport.qh"
#include "override.qh"
.entity overrider, overrider_self;
.float overrider_priority;
// ===================================================================== //
/* Let's make my life simpler when I add new ones, mmmkay? */
#define all_funcs() \
one_func(float(), f_v, th_takeitem, (), return, FALSE); \
\
one_func(void(entity missile), v_e, th_attack, (missile), , ); \
\
one_func(float(float dmg), f_f, th_takedamage, (dmg), return, FALSE); \
one_func(float(float dmg), f_f, th_dealdamage, (dmg), return, dmg); \
\
one_func(void(), v_v, th_die, (), , ); \
one_func(void(), v_v, th_kill, (), , ); \
\
one_func(void(), v_v, prethink, (), , ); \
one_func(void(), v_v, actthink, (), , ); \
one_func(void(), v_v, postthink, (), , ); \
\
one_func(float(vector org), f_c, th_teleport, (org), return, TRUE); \
\
one_func(float(entity missile), f_e, th_projectile, (missile), return, TRUE)
#define all_types() \
one_type(void(), v_v); \
one_type(float(), f_v); \
one_type(void(entity ent), v_e); \
one_type(float(float flt), f_f); \
one_type(float(vector vec), f_c); \
one_type(float(entity ent), f_e)
// ===================================================================== //
/* default passthru functions */
#define one_func(type1,type2,func,args,return,val) \
type1 _passthru_##func = { \
local entity ovr; \
ovr = override_findself(); \
if (ovr.func) \
return ovr.func##args; \
return val; \
}
all_funcs();
#undef one_func
/* for the override_set_FUNCTION macros in override.qh */
#define one_type(type1,type2) \
void(entity e, .##type1 fld, type1 func) override_set_##type2 = {\
if (e.overrider) \
e.overrider.fld = func; \
else \
e.fld = func; \
}
all_types();
#undef one_type
// ===================================================================== //
void(entity e1, entity e2) _override_swap = {
#define one_type(type1,type2) local type1 t_##type2
all_types();
#undef one_type
/* Swap all the functions */
#define one_func(type1,type2,func,args,return,val) \
t_##type2 = e1.func; \
e1.func = e2.func; \
e2.func = t_##type2
all_funcs();
#undef one_func
};
// ===================================================================== //
entity(entity e, string override_class, float priority) override_create = {
local entity ovr, ovr2;
for (ovr = e.overrider; ovr; ovr = ovr.overrider) {
if (ovr.classname == override_class) {
ovr2 = ovr.overrider;
if (!ovr2) ovr2 = e;
_override_swap(ovr, ovr2);
return ovr;
}
}
/* Move to the tail.. */
for (ovr = e; ovr.overrider; ovr = ovr.overrider) {
if (ovr.overrider.overrider_priority > priority)
break;
}
ovr2 = ovr.overrider;
ovr.overrider = spawn(override_class);
ovr.overrider.owner = ovr;
ovr.overrider.overrider = ovr2;
if (ovr2) ovr2.owner = ovr.overrider;
if (!ovr2) ovr2 = e;
ovr = ovr.overrider;
ovr.overrider_priority = priority;
ovr.goalentity = ovr2;
/* Set default passthru funcs for ovr */
#define one_func(type1,type2,func,args,return,val) \
ovr.func = _passthru_##func
all_funcs();
#undef one_func
return ovr;
};
void(entity ovr) override_finalize = {
_override_swap(ovr, ovr.goalentity);
};
entity() override_findself = {
local entity ovrself;
ovrself = self.overrider_self;
if (!ovrself) {
/* Move to the end of the list */
for (ovrself = self.overrider; ovrself.overrider; ovrself = ovrself.overrider) ;
}
self.overrider_self = ovrself.owner;
if (self.overrider_self == self)
self.overrider_self = world;
return ovrself;
};
void() override_halt = {
self.overrider_self = world;
};
void(entity e, entity ovr) override_destroy = {
local entity ovr2;
ovr2 = ovr.overrider;
if (!ovr2) ovr2 = e;
/* Copy the funcs from ovr to ovr2 */
#define one_func(type1,type2,func,args,return,val) \
ovr2.func = ovr.func
all_funcs();
#undef one_func
if (ovr.overrider) ovr.overrider.owner = ovr.owner;
ovr.owner.overrider = ovr.overrider;
ovr.think = SUB_remove;
ovr.nextthink = time;
};

49
klik/override.qh Normal file
View file

@ -0,0 +1,49 @@
#ifndef OVERRIDE_qh
#define OVERRIDE_qh 1
@extern {
/* Returns an overrider with matching class, creating one if needed */
entity(entity e, string override_class, float priority) override_create;
/* Finalizes the above, call this once you set what you want to override. */
void(entity ovr) override_finalize;
/* Use this in your overrider to get your entity. Call it _EXACTLY ONCE_ per overrider */
entity() override_findself;
/* This _MUST_ be called if you don't continue down the chain! */
void() override_halt;
/* Guess. */
void(entity e, entity ovr) override_destroy;
/* FIXME: Use 'any' type when compiler supports it */
void(entity e, .void() fld, void() func) override_set_v_v;
void(entity e, .float(entity ent) fld, float(entity ent) func) override_set_f_e;
void(entity e, .float(float flt) fld, float(float flt) func) override_set_f_f;
void(entity e, .float() fld, float() func) override_set_f_v;
void(entity e, .float(vector vec) fld, float(vector vec) func) override_set_f_c;
void(entity e, .float(entity ent) fld, float(entity ent) func) override_set_f_e;
#define override_set_th_takeitem(e, func) override_set_f_v(e, th_takeitem, func)
#define override_set_th_attack(e, func) override_set_f_e(e, th_attack, func)
#define override_set_th_takedamage(e, func) override_set_f_f(e, th_takedamage, func)
#define override_set_th_dealdamage(e, func) override_set_f_f(e, th_dealdamage, func)
#define override_set_th_die(e, func) override_set_v_v(e, th_die, func)
#define override_set_th_kill(e, func) override_set_v_v(e, th_kill, func)
#define override_set_prethink(e, func) override_set_v_v(e, prethink, func)
#define override_set_actthink(e, func) override_set_v_v(e, actthink, func)
#define override_set_postthink(e, func) override_set_v_v(e, postthink, func)
#define override_set_th_teleport(e, func) override_set_f_c(e, th_teleport, func)
#define override_set_th_projectile(e, func) override_set_f_e(e, th_projectile, func)
};
#endif

140
klik/progdefs.h Normal file
View file

@ -0,0 +1,140 @@
/* file generated by qcc, do not modify */
typedef struct
{ int pad[28];
int self;
int other;
int world;
float time;
float frametime;
int newmis;
float force_retouch;
string_t mapname;
float serverflags;
float total_secrets;
float total_monsters;
float found_secrets;
float killed_monsters;
float parm1;
float parm2;
float parm3;
float parm4;
float parm5;
float parm6;
float parm7;
float parm8;
float parm9;
float parm10;
float parm11;
float parm12;
float parm13;
float parm14;
float parm15;
float parm16;
vec3_t v_forward;
vec3_t v_up;
vec3_t v_right;
float trace_allsolid;
float trace_startsolid;
float trace_fraction;
vec3_t trace_endpos;
vec3_t trace_plane_normal;
float trace_plane_dist;
int trace_ent;
float trace_inopen;
float trace_inwater;
int msg_entity;
func_t main;
func_t StartFrame;
func_t PlayerPreThink;
func_t PlayerPostThink;
func_t ClientKill;
func_t ClientConnect;
func_t PutClientInServer;
func_t ClientDisconnect;
func_t SetNewParms;
func_t SetChangeParms;
} globalvars_t;
typedef struct
{
float modelindex;
vec3_t absmin;
vec3_t absmax;
float ltime;
float lastruntime;
float movetype;
float solid;
vec3_t origin;
vec3_t oldorigin;
vec3_t velocity;
vec3_t angles;
vec3_t avelocity;
string_t classname;
string_t model;
float frame;
float skin;
float effects;
vec3_t mins;
vec3_t maxs;
vec3_t size;
func_t touch;
func_t use;
func_t think;
func_t blocked;
float nextthink;
int groundentity;
float health;
float frags;
float weapon;
string_t weaponmodel;
float weaponframe;
float currentammo;
float ammo_shells;
float ammo_nails;
float ammo_rockets;
float ammo_cells;
float items;
float takedamage;
int chain;
float deadflag;
vec3_t view_ofs;
float button0;
float button1;
float button2;
float impulse;
float fixangle;
vec3_t v_angle;
string_t netname;
int enemy;
float flags;
float colormap;
float team;
float max_health;
float teleport_time;
float armortype;
float armorvalue;
float waterlevel;
float watertype;
float ideal_yaw;
float yaw_speed;
int aiment;
int goalentity;
float spawnflags;
string_t target;
string_t targetname;
float dmg_take;
float dmg_save;
int dmg_inflictor;
int owner;
vec3_t movedir;
string_t message;
float sounds;
string_t noise;
string_t noise1;
string_t noise2;
string_t noise3;
} entvars_t;
#define PROGHEADER_CRC 54730

46
klik/progs.src Normal file
View file

@ -0,0 +1,46 @@
../qwprogs.dat
system.qh
server.qc
worldspawn.qc
client.qc
spectate.qc
refcount.qc
sz_watch.qc
math.qc
entnum.qc
misc.qc
effect.qc
teleport.qc
delays.qc
bodyque.qc
damage.qc
equip.qc
equipid.qc
weapon.qc
weapon_g.qc
w_void.qc
w_axe.qc
w_shotgun.qc
w_nailgun.qc
w_grenade_launcher.qc
w_rocket_launcher.qc
w_lightning_gun.qc
act.qc
act_player.qc
act_dead.qc
mdl.qc
mdl_void.qc
mdl_player.qc
mdl_eyes.qc
menu.qc
menus.qc
override.qc
mapents_util.qc
mapents.qc
items.qc
mapents_triggers.qc
mapents_movewall.qc
mapents_traps.qc
id_compat.qc
mapents_items.qc
mapents_powerup.qc

6
klik/protocol.qh Normal file
View file

@ -0,0 +1,6 @@
#ifndef PROTOCOL_qh
#define PROTOCOL_qh 1
#include SYSTEM_DIR "protocol.qh"
#endif

96
klik/qw/builtins.qc Normal file
View file

@ -0,0 +1,96 @@
/* Builtin functions */
entity() BUILTIN_spawn = #14;
void(entity e) remove = #15;
void(entity e, vector o) setorigin = #2;
void(entity e, string m) setmodel = #3; // set movetype and solid first
void(entity e, vector min, vector max) setsize = #4;
string(string s) precache_sound = #19;
string(string s) precache_model = #20;
string(string s) precache_file = #68; // no effect except for -copy
string(string s) precache_sound2 = #76; // registered version only
string(string s) precache_model2 = #75; // registered version only
string(string s) precache_file2 = #77; // registered version only
void(float style, string value) lightstyle = #35;
// debug functions
void() BUILTIN_break = #6; // shatter progs
void(string e, ...) error = #10;
void(string e, ...) objerror = #11;
void() coredump = #28; // prints all edicts
void() traceon = #29; // turns statment trace on
void() traceoff = #30;
void(entity e, float chan, string samp, float vol, float atten) sound = #8;
void(vector ang) makevectors = #1; // sets v_forward, etc globals
vector(vector v) normalize = #9;
float(vector v) vlen = #12;
float(vector v) vectoyaw = #13;
vector(vector v) vectoangles = #51;
vector(entity e, float speed) aim = #44; // returns the shooting vector
float() random = #7; // returns 0 - 1
string(float f) ftos = #26;
float(string s) stof = #81; // convert string to float
string(vector v) vtos = #27;
float(float v) rint = #36; // round to nearest int
float(float v) floor = #37; // largest integer <= v
float(float v) ceil = #38; // smallest integer >= v
float(float f) fabs = #43;
// sets trace_* globals
// nomonsters can be:
// An entity will also be ignored for testing if forent == test,
// forent->owner == test, or test->owner == forent
// a forent of world is ignored
void(vector v1, vector v2, float nomonsters, entity forent) traceline = #16;
float(vector v) pointcontents = #41; // returns a CONTENT_*
float(entity e) checkbottom = #40; // true if self is on ground
float() droptofloor = #34; // TRUE if landed on floor
float(float yaw, float dist) walkmove = #32; // returns TRUE or FALSE
void(float step) movetogoal = #67;
entity() checkclient = #17; // returns a client to look for
entity(entity start, .string fld, string match) find = #18;
entity(vector org, float rad) findradius = #22;
entity(entity e) nextent = #47; // for looping through all ents
void(float level, string s, ...) bprint = #23;
void(entity client, float level, string s, ...) sprint = #24;
void(entity client, string s, ...) centerprint = #73; // sprint, but in middle
void(string s, ...) dprint = #25;
void(entity e) eprint = #31; // prints an entire edict
float(string s) cvar = #45; // return cvar.value
void(string var, string val) cvar_set = #72; // sets cvar.value
string(entity e, string key) infokey = #80; // get a key value (world = serverinfo)
void(string s1, ...) localcmd = #46; // put string into local que
void(entity client, string s) stuffcmd = #21;
void() ChangeYaw = #49; // turn towards self.ideal_yaw
// at self.yaw_speed
// direct client message generation
void(float to, float f) WriteByte = #52;
void(float to, float f) WriteChar = #53;
void(float to, float f) WriteShort = #54;
void(float to, float f) WriteLong = #55;
void(float to, float f) WriteCoord = #56;
void(float to, float f) WriteAngle = #57;
void(float to, string s) WriteString = #58;
void(float to, entity s) WriteEntity = #59;
void(vector where, float set) multicast = #82; // sends the temp message to a set
void(entity e) BUILTIN_makestatic = #69;
void(string s) changelevel = #70;
void(vector pos, string samp, float vol, float atten) BUILTIN_ambientsound = #74;
void(entity e) setspawnparms = #78; // set parm1... to the
// values at level start
// for coop respawn
void(entity killer, entity killee) logfrag = #79; // add to stats

10
klik/qw/builtins.qh Normal file
View file

@ -0,0 +1,10 @@
#ifndef QW_BUILTINS_qh
#define QW_BUILTINS_qh 1
@extern {
#include "qw/builtins.qc"
};
#include "sz_watch.qh"
#endif

96
klik/qw/effect.qc Normal file
View file

@ -0,0 +1,96 @@
#include "common.qh"
#include "qw/protocol.qh"
#include "effect.qh"
#include "misc.qh"
void() effect_muzzleflash = {
WriteByte(MSG_MULTICAST, SVC_MUZZLEFLASH);
WriteEntity(MSG_MULTICAST, self);
multicast(self.origin, MULTICAST_PVS);
};
void(entity e) effect_smallkick = {
if (!is_cl(e))
return;
msg_entity = e;
WriteByte(MSG_ONE, SVC_SMALLKICK);
};
void(vector org, vector dir, float d) effect_blood = {
d = d / 5;
if (d < 3) d = 3;
if (d > 255) d = 255;
WriteByte(MSG_MULTICAST, SVC_TEMPENTITY);
WriteByte(MSG_MULTICAST, TE_BLOOD);
WriteByte(MSG_MULTICAST, d);
WriteCoord(MSG_MULTICAST, org_x);
WriteCoord(MSG_MULTICAST, org_y);
WriteCoord(MSG_MULTICAST, org_z);
multicast(org, MULTICAST_PVS);
};
void(vector org, vector vel, float d) effect_gun_spark = {
WriteByte(MSG_MULTICAST, SVC_TEMPENTITY);
WriteByte(MSG_MULTICAST, TE_GUNSHOT);
WriteByte(MSG_MULTICAST, d);
WriteCoord(MSG_MULTICAST, org_x);
WriteCoord(MSG_MULTICAST, org_y);
WriteCoord(MSG_MULTICAST, org_z);
multicast(org, MULTICAST_PVS);
};
void(vector org, vector vel) effect_nail_spark = {
WriteByte(MSG_MULTICAST, SVC_TEMPENTITY);
WriteByte(MSG_MULTICAST, TE_SPIKE);
WriteCoord(MSG_MULTICAST, org_x);
WriteCoord(MSG_MULTICAST, org_y);
WriteCoord(MSG_MULTICAST, org_z);
multicast(org, MULTICAST_PHS);
};
void(vector org) effect_explosion = {
WriteByte(MSG_MULTICAST, SVC_TEMPENTITY);
WriteByte(MSG_MULTICAST, TE_EXPLOSION);
WriteCoord(MSG_MULTICAST, org_x);
WriteCoord(MSG_MULTICAST, org_y);
WriteCoord(MSG_MULTICAST, org_z);
multicast(org, MULTICAST_PHS);
};
void(vector org) effect_teleport_fog = {
local float r;
local string snd;
r = random() * 5;
if (r < 1) snd = "misc/r_tele1.wav";
else if (r < 2) snd = "misc/r_tele2.wav";
else if (r < 3) snd = "misc/r_tele3.wav";
else if (r < 4) snd = "misc/r_tele4.wav";
else snd = "misc/r_tele5.wav";
WriteByte(MSG_MULTICAST, SVC_TEMPENTITY);
WriteByte(MSG_MULTICAST, TE_TELEPORT);
WriteCoord(MSG_MULTICAST, org_x);
WriteCoord(MSG_MULTICAST, org_y);
WriteCoord(MSG_MULTICAST, org_z);
multicast(org, MULTICAST_PHS);
sound_vector(org, snd, 1, ATTN_NORM);
};
void(entity from, vector p1, vector p2) effect_lightning2 = {
WriteByte(MSG_MULTICAST, SVC_TEMPENTITY);
WriteByte(MSG_MULTICAST, TE_LIGHTNING2);
WriteEntity(MSG_MULTICAST, from);
WriteCoord(MSG_MULTICAST, p1_x);
WriteCoord(MSG_MULTICAST, p1_y);
WriteCoord(MSG_MULTICAST, p1_z);
WriteCoord(MSG_MULTICAST, p2_x);
WriteCoord(MSG_MULTICAST, p2_y);
WriteCoord(MSG_MULTICAST, p2_z);
multicast(p1, MULTICAST_PHS);
};

40
klik/qw/protocol.qh Normal file
View file

@ -0,0 +1,40 @@
#ifndef QW_PROTOCOL_qh
#define QW_PROTOCOL_qh 1
// protocol bytes
#define SVC_PRINT 8
#define SVC_UPDATEFRAGS 14
#define SVC_MAKESTATIC 20
#define SVC_TEMPENTITY 23
#define SVC_CENTERPRINT 26
#define SVC_KILLEDMONSTER 27
#define SVC_FOUNDSECRET 28
#define SVC_INTERMISSION 30
#define SVC_FINALE 31
#define SVC_CDTRACK 32
#define SVC_SELLSCREEN 33
#define SVC_SMALLKICK 34
#define SVC_BIGKICK 35
#define SVC_UPDATEPING 36
#define SVC_UPDATEENTERTIME 37
#define SVC_MUZZLEFLASH 39
#define SVC_UPDATEUSERINFO 40
#define SVC_UPDATEPL 53
// temp entities
#define TE_SPIKE 0
#define TE_SUPERSPIKE 1
#define TE_GUNSHOT 2
#define TE_EXPLOSION 3
#define TE_TAREXPLOSION 4
#define TE_LIGHTNING1 5
#define TE_LIGHTNING2 6
#define TE_WIZSPIKE 7
#define TE_KNIGHTSPIKE 8
#define TE_LIGHTNING3 9
#define TE_LAVASPLASH 10
#define TE_TELEPORT 11
#define TE_BLOOD 12
#define TE_LIGHTNINGBLOOD 13
#endif

207
klik/qw/system.qc Normal file
View file

@ -0,0 +1,207 @@
/* THIS FILE MUST BE FIRST. */
/* It contains system globals and fields. */
// ========================================================================== //
/* Do not modify, this is the C system globals structure */
entity self;
entity other;
entity world;
float time;
float frametime;
entity newmis; // if this is set, the entity that just
// run created a new missile that should
// be simulated immediately
float force_retouch; // force all entities to touch triggers
// next frame. this is needed because
// non-moving things don't normally scan
// for triggers, and when a trigger is
// created (like a teleport trigger), it
// needs to catch everything.
// decremented each frame, so set to 2
// to guarantee everything is touched
string mapname;
float serverflags; // propagated from level to level, used to
// keep track of completed episodes
float total_secrets;
float total_monsters;
float found_secrets; // number of secrets found
float killed_monsters; // number of monsters killed
// spawnparms are used to encode information about clients across server
// level changes
float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16;
//
// global variables set by built in functions
//
vector v_forward, v_up, v_right; // set by makevectors()
// set by traceline / tracebox
float trace_allsolid;
float trace_startsolid;
float trace_fraction;
vector trace_endpos;
vector trace_plane_normal;
float trace_plane_dist;
entity trace_ent;
float trace_inopen;
float trace_inwater;
entity msg_entity; // destination of single entity writes
//
// required prog functions
//
#ifndef QW_SYSTEM_qh
@system {
#endif
void() main; // only for testing
void() StartFrame;
void() PlayerPreThink;
void() PlayerPostThink;
void() ClientKill;
void() ClientConnect;
void() PutClientInServer; // call after setting the parm1... parms
void() ClientDisconnect;
void() SetNewParms; // called when a client first connects to
// a server. sets parms so they can be
// saved off for restarts
void() SetChangeParms; // call to set parms for self so they can
// be saved for a level transition
void end_sys_globals; // flag for structure dumping
#ifndef QW_SYSTEM_qh
};
#endif
/* End of system globals */
// ========================================================================== //
// ========================================================================== //
/* Do not change. These are the system fields required by C code */
/* (*** = do not set in prog code, maintained by C code) */
.float modelindex; // *** model index in the precached list
.vector absmin, absmax; // *** origin + mins / maxs
.float ltime; // local time for entity
.float lastruntime; // *** to allow entities to run out of sequence
.float movetype;
.float solid;
.vector origin; // *** use setorigin
.vector oldorigin; // ***
.vector velocity;
.vector angles;
.vector avelocity;
.string classname; // spawn function
.string model;
.float frame;
.float skin;
.float effects;
.vector mins, maxs; // bounding box extents reletive to origin
.vector size; // *** maxs - mins, use setsize
.void() touch;
.void() use;
.void() think;
.void() blocked; // for doors or plats, called when can't push other
.float nextthink;
.entity groundentity;
// stats
.float health;
.float frags;
.float weapon; // one of the IT_SHOTGUN, etc flags
.string weaponmodel;
.float weaponframe;
.float currentammo;
.float ammo_shells, ammo_nails, ammo_rockets, ammo_cells;
.float items; // bit flags
.float takedamage;
.entity chain;
.float deadflag;
.vector view_ofs; // add to origin to get eye point
.float button0; // fire
.float button1; // use
.float button2; // jump
.float impulse; // weapon changes
.float fixangle;
.vector v_angle; // view / targeting angle for players
.string netname;
.entity enemy;
.float flags;
.float colormap;
.float team;
.float max_health; // players maximum health is stored here
.float teleport_time; // don't back up
.float armortype; // save this fraction of incoming damage
.float armorvalue;
.float waterlevel; // 0 = not in, 1 = feet, 2 = waist, 3 = eyes
.float watertype; // a contents value
.float ideal_yaw;
.float yaw_speed;
.entity aiment;
.entity goalentity; // a movetarget or an enemy
.float spawnflags;
.string target;
.string targetname;
// damage is accumulated through a frame. and sent as one single
// message, so the super shotgun doesn't generate huge messages
.float dmg_take;
.float dmg_save;
.entity dmg_inflictor;
.entity owner; // who launched a missile
.vector movedir; // mostly for doors, but also used for waterjump
.string message; // trigger messages
.float sounds; // either a cd track number or sound number
.string noise, noise1, noise2, noise3; // contains names of wavs to play
void end_sys_fields; // flag for structure dumping
/* End of system fields */
// ========================================================================== //
// ========================================================================== //

8
klik/qw/system.qh Normal file
View file

@ -0,0 +1,8 @@
#ifndef QW_SYSTEM_qh
#define QW_SYSTEM_qh 1
@extern {
#include "qw/system.qc"
};
#endif

135
klik/qw/sz_watch.qc Normal file
View file

@ -0,0 +1,135 @@
#include "common.qh"
#include "server.qh"
#include "protocol.qh"
#include "misc.qh"
/*
All this crap is to make sure we don't overflow the signon
buffer or message buffer, since Quake doesn't bother to
just split the messages for us.
And since, at best, it will crash with an error if the buffer
gets overflowed.
*/
// ========================================================================
// Don't change these unless you know what you're doing.
#define SV_SIGNON_BUFFERS 8
#define SV_SIGNON_BUFFER_SWAP 512
// QF == 1, twilight/stock == 0
#define SV_FLUSHSIGNON_BREAKS 1
#define SV_MAX_DATAGRAM 1450
#define SV_FRAME_OVERHEAD 725 /* Wild guess. */
#define SIZEOF_BASELINE 22
#define SIZEOF_AMBIENTSOUND 16
#define SIZEOF_MAKESTATIC 20
// ========================================================================
float sv_signon_buf_remaining;
float sv_signon_remaining;
float sv_frame_remaining;
// =================
float(float space) SZ_GetSpace_frame = {
if (sv_frame_remaining < space)
return FALSE;
sv_frame_remaining -= space;
return TRUE;
};
entity SZ_self;
float(float space) SZ_GetSpace_signon = {
if (sv_spawning || !SV_FLUSHSIGNON_BREAKS) {
if (self != SZ_self) {
SZ_self = self;
if (sv_signon_remaining < (SV_MAX_DATAGRAM - 512)) {
if (--sv_signon_buf_remaining <= 0)
return FALSE;
sv_signon_remaining = SV_MAX_DATAGRAM;
}
}
}
if (sv_signon_remaining < space)
return FALSE;
sv_signon_remaining -= space;
return TRUE;
};
// =================
void() SZ_init = {
sv_signon_buf_remaining = SV_SIGNON_BUFFERS;
sv_signon_remaining = SV_MAX_DATAGRAM;
while (self = nextent(self))
SZ_GetSpace_signon(SIZEOF_BASELINE);
self = world;
};
void() SZ_frame = {
sv_frame_remaining = SV_MAX_DATAGRAM - SV_FRAME_OVERHEAD;
};
// =================
void(entity e) makestatic = {
e.solid = SOLID_NOT;
e.movetype = MOVETYPE_NONE;
e.velocity = '0 0 0';
e.avelocity = '0 0 0';
e.nextthink = -1;
/* No more space? Just let it be... */
if (!SZ_GetSpace_signon(SIZEOF_MAKESTATIC))
return;
if (!sv_spawning) {
if (!SZ_GetSpace_frame(SIZEOF_MAKESTATIC)) {
self.think = SUB_makestatic;
self.nextthink = time + sv_mintic;
return;
}
WriteByte(MSG_ALL, SVC_MAKESTATIC);
WriteByte(MSG_ALL, e.modelindex);
WriteByte(MSG_ALL, e.frame);
WriteByte(MSG_ALL, e.colormap);
WriteByte(MSG_ALL, e.skin);
WriteCoord(MSG_ALL, e.origin_x);
WriteCoord(MSG_ALL, e.origin_y);
WriteCoord(MSG_ALL, e.origin_z);
WriteAngle(MSG_ALL, e.angles_x);
WriteAngle(MSG_ALL, e.angles_y);
WriteAngle(MSG_ALL, e.angles_z);
}
BUILTIN_makestatic(e);
};
void(vector pos, string samp, float vol, float atten) ambientsound = {
if (!sv_spawning)
error("ambientsound after spawn functions\n");
SZ_GetSpace_signon(SIZEOF_AMBIENTSOUND);
/* Do it anyway */
BUILTIN_ambientsound(pos, samp, vol, atten);
};

12
klik/qw/sz_watch.qh Normal file
View file

@ -0,0 +1,12 @@
#ifndef SZ_WATCH_qh
#define SZ_WATCH_qh 1
float sv_spawning;
void() SZ_init;
void() SZ_frame;
void(entity e) makestatic;
void(vector pos, string samp, float vol, float atten) ambientsound;
#endif

2
klik/regex Executable file
View file

@ -0,0 +1,2 @@
sed -e 's/float\([ ]\+[A-Za-z_][A-Za-z_0-9]*[ ]\+\)=[ ]\+\(-\?[0-9.]\+\);/#define\1\2/'
#sed -e 's!\(#define.*\)//\(.*\)!\1/*\2 */!'

5
klik/regex.txt Normal file
View file

@ -0,0 +1,5 @@
float\([ ]\+[A-Za-z_][A-Za-z_0-9]*[ ]\+\)=[ ]\+\(-\?[0-9.]\+\);
#define\1\2
\(#define.*\)//\(.*\)
\1/*\2 */

111
klik/server.qc Normal file
View file

@ -0,0 +1,111 @@
#include "common.qh"
#include "server.qh"
#include "damage.qh"
#include "bodyque.qh"
#include "weapon.qh"
#include "client.qh"
#include "sz_watch.qh"
#include "mdl_player.qh"
#include "mdl_eyes.qh"
#include "act_player.qh"
#include "delays.qh"
#define SV_FRAMES_BEFORE_SPAWN 3
void() main = {
local entity walk;
/* Must be first. */
max_clients = 0;
walk = world;
while (walk = nextent(walk)) max_clients++;
sv_spawning = SV_FRAMES_BEFORE_SPAWN;
damage_init();
bodyque_init();
weapon_init();
client_init();
SZ_init();
mdl_player_init();
mdl_eyes_init();
act_player_init();
};
float players_frame_started;
void() StartFrame = {
if (sv_spawning) {
sv_spawning = sv_spawning - 1;
if (!sv_spawning) {
if (!intermission_head)
intermission_head = spawn_head;
if (!spawn_head)
error("Unable to find a spawn point.\n");
}
}
SZ_frame();
rocket_jump = stof(infokey(world, "rj"));
if (rocket_jump <= 1) rocket_jump = 0;
sv_mintic = cvar("sv_mintic");
sv_maxtic = cvar("sv_maxtic");
sv_gravity = cvar("sv_gravity");
sv_stopspeed = cvar("sv_stopspeed");
sv_maxspeed = cvar("sv_maxspeed");
sv_spectatormaxspeed = cvar("sv_spectatormaxspeed");
sv_accelerate = cvar("sv_accelerate");
sv_airaccelerate = cvar("sv_airaccelerate");
sv_wateraccelerate = cvar("sv_wateraccelerate");
sv_friction = cvar("sv_friction");
sv_waterfriction = cvar("sv_waterfriction");
cl_rollangle = cvar("cl_rollangle");
cl_rollspeed = cvar("cl_rollspeed");
PlayerStartFrame();
players_frame_started = -1;
};
/* This is really called by QSG engines */
// void() EndFrame = { };
void() PlayerStartFrame = {
if (players_frame_started == -1) {
/* First player after StartFrame */
players_frame_started = TRUE;
return;
}
if (players_frame_started)
return;
players_frame_started = TRUE;
delays_swapin_stats_all();
};
void() PlayerEndFrame = {
/* Unfortunately, a newmis can us damage this frame,
after our postthink has been called. Damn. */
/* We just force an update this frame for now. */
if (newmis) {
delays_force_update_all();
} else {
players_frame_started = FALSE;
delays_swapout_stats_all();
}
};

27
klik/server.qh Normal file
View file

@ -0,0 +1,27 @@
#ifndef SERVER_qh
#define SERVER_qh 1
@extern {
float max_clients;
// Various cvars [possibly] referenced by QC
float rocket_jump;
float sv_mintic, sv_maxtic;
float sv_gravity;
float sv_stopspeed, sv_maxspeed, sv_spectatormaxspeed;
float sv_accelerate, sv_airaccelerate, sv_wateraccelerate;
float sv_friction, sv_waterfriction;
float cl_rollangle, cl_rollspeed;
void() StartFrame;
void() PlayerStartFrame;
void() PlayerEndFrame;
};
#endif

16
klik/spectate.qc Normal file
View file

@ -0,0 +1,16 @@
#include "common.qh"
// Called when a spectator connects
void() SpectatorConnect = {
bprint(PRINT_MEDIUM, "Spectator ", self.netname, " entered the game.\n");
};
// Called when a spectator disconnects
void() SpectatorDisconnect = {
bprint(PRINT_MEDIUM, "Spectator ", self.netname, " left the game.\n");
};
// Called around the same time as player thinks?
void() SpectatorThink = {
self.impulse = 0;
};

84
klik/system.qc Normal file
View file

@ -0,0 +1,84 @@
void() NOTHING_function = {};
// ========================================================================== //
// ========================================================================== //
/* Fields in maps */
// not used by the gamecode, but some utils leave it.
.float light_lev;
.float style;
// worldspawn
.string wad;
.string map;
.float worldtype; // 0=medieval 1=metal 2=base
// various triggers
.string killtarget;
.float wait; // time from firing to restarting
.float delay; // time from activation to firing
.float count; // for counting triggers
// plats, doors, trains, etc
.float speed;
.float dmg; // damage done by door when hit
.float lip;
.float state;
.float height;
// secret doors
.float t_length, t_width;
// various
.vector mangle; // angle at start
/* Custom klik stuff, to be used in maps */
// for sounds
.float volume, attenuation;
.string noise4;
.string noise5, noise6; // can't activate, can activate.
.string noise7; // for items, respawn
// ========================================================================== //
// ========================================================================== //
#if 0
// used by QSG engines
.float alpha, scale;
.float glow_size, glow_color;
.vector colormod;
#endif
// plats, doors, trains, etc
.vector pos1, pos2;
.void() think1;
// Per-player modifiers
.float gravity; // Gravity Multiplier (0 to 1.0)
.float maxspeed; // Used to set Maxspeed on a player
// ========================================================================== //
// ========================================================================== //
.float mass; // for projectile collisions
.float currency;
.float max_armor;
.float max_ammo_shells;
.float max_ammo_nails;
.float max_ammo_rockets;
.float max_ammo_cells;
.float air_finished; // Air left in lungs
.float water_finished; // swim sound
.float pain_finished; // pain sound
// ========================================================================== //
// ========================================================================== //

8
klik/system.qh Normal file
View file

@ -0,0 +1,8 @@
#ifndef SYSTEM_qh
#define SYSTEM_qh 1
@extern {
#include "system.qc"
};
#endif

91
klik/teleport.qc Normal file
View file

@ -0,0 +1,91 @@
#include "common.qh"
#include "mapents_util.qh"
#include "damage.qh"
#include "effect.qh"
#include "teleport.qh"
void() _deathmsg_teleport = {
local string att_nname, def_nname;
def_nname = name(self);
att_nname = name(self.dmg_attacker);
if (self.dmg_inflictor.owner == self)
bprint(PRINT_DEATH, "Satan's power deflects ", att_nname, "'s telefrag.\n");
else
bprint(PRINT_DEATH, def_nname, " was telefragged by ", att_nname, ".\n");
};
void() _teleport_death_touch = {
if (self.owner == other)
return;
ghost_inflictor.classname = "TELEPORT_DEATH";
ghost_inflictor.dmg = DAMAGE_SHOULDDIE;
ghost_inflictor.mass = 800;
ghost_inflictor.velocity = '0 0 0';
ghost_inflictor.lip = 64;
ghost_inflictor.speed = 1000;
ghost_inflictor.owner = self.owner;
damage(other, self.owner, ghost_inflictor, DAMAGE_SHOULDDIE, _deathmsg_teleport);
};
void(vector org, entity death_owner) _teleport_death_spawn = {
local entity death;
death = spawn("TELEDEATH");
death.owner = death_owner;
death.solid = SOLID_TRIGGER;
setsize(death, death_owner.mins - '1 1 1', death_owner.maxs + '1 1 1');
setorigin(death, org);
death.touch = _teleport_death_touch;
death.think = SUB_remove;
death.nextthink = time + 0.1;
force_retouch = 2;
};
void(entity e, entity spot) teleport = {
local float spd;
if (e.th_teleport) {
local entity oldself, oldother;
local float do_teleport;
oldself = self;
oldother = other;
self = e;
other = spot;
do_teleport = self.th_teleport(other.origin);
self = oldself;
other = oldother;
if (!do_teleport)
return;
}
spd = vlen(e.velocity);
if (spd < 200)
spd = 200;
setorigin(e, spot.origin);
e.angles = spot.angles;
e.fixangle = TRUE;
e.teleport_time = 0.1;
makevectors(e.angles);
e.velocity = v_forward*spd;
if (is_living(e))
_teleport_death_spawn(spot.origin, e);
effect_teleport_fog(spot.origin);
};

12
klik/teleport.qh Normal file
View file

@ -0,0 +1,12 @@
#ifndef TELEPORT_qh
#define TELEPORT_qh 1
@extern {
.float(vector org) th_teleport;
void(entity e, entity spot) teleport;
};
#endif

View file

@ -0,0 +1,64 @@
menu_equip_primary
"\b=\b=\b=\b Primary Weapons \b=\b=\b=\b"
1 "Sniper Riffle" 4000
2 "Chaingun" 3000
3 "Rocket Launcher" 3000
4 "Grenade Launcher" 2200
5 "Lightning Gun" 2200
6 "Super Nailgun" 2000
""
8 "Previous" { } { return ITEM_DISABLED; }
9 "Next" { menu_set(menu_equip_secondary); nomenu = 1; }
10 "Done" { menu_set(SUB_Null); nomenu = 1; }
k_menu_secondary
"\b=\b=\b=\b Secondary Weapons \b=\b=\b=\b"
1 "Med-Kit" 1550 {
%6$s
if (status == FALSE || status == -1)
item_sell(self, ITEM___AUTO_MED_KIT, ITEM___AUTO_MED_KIT_PRICE);
}
2 "\b..\bAuto Med-Kit" 750 {
if (item_query(self, ITEM_MED_KIT)) { %6$s }
} {
local float status;
status = item_query(self, ITEM_MED_KIT);
if (!status) return ITEM_DISABLED;
status = item_query(self, %1$s);
if (!status) return ITEM_DEFAULT;
return ITEM_SELECTED;
}
3 "Knife" 700
4 "Super Shotgun" 500
5 "Laser" 500
6 "Flame Thrower" 500
""
8 "Previous" { menu_set(menu_equip_primary); nomenu = 1; }
9 "Next" { menu_set(menu_equip_tertiary); nomenu = 1; }
10 "Done" { menu_set(SUB_Null); nomenu = 1; }
menu_equip_tertiary
"\b=\b=\b=\b Tertiary Weapons \b=\b=\b=\b"
1 "Nailgun" 400
2 "Shotgun" 50
""
"More weapons coming soon."
""
""
""
8 "Previous" { menu_set(menu_equip_secondary); nomenu = 1; }
9 "Next" { menu_set(menu_equip_upgrades); nomenu = 1; }
10 "Done" { menu_set(SUB_Null); nomenu = 1; }
k_menu_upgrades
"\b=\b=\b=\b Upgrades \b=\b=\b=\b"
1 "Cluster Rockets" 1000
2 "Pyro Toys" 1000
3 "Extra Ammo" 500
""
"More upgrades coming soon."
""
""
8 "Previous" { menu_set(k_menu_equip_tertiary); nomenu = 1; }
9 "Next" { } { return K_DISABLED; }
10 "Done" { menu_set(SUB_Null); nomenu = 1; }

414
klik/unused/menusmarf.l Normal file
View file

@ -0,0 +1,414 @@
%{
#include <string.h>
#include "menusmarf.tab.c"
static char str_buf[16384], *str_buf_head;
static int caller, parens;
static int bronze;
static char *qccpy(char *buffer, const char *str);
%}
%s s_string
%s s_comment
%s s_code
%s s_code_string
%%
<INITIAL>{
[-+]?([0-9]+\.?)|(\.[0-9]+)|([0-9]+\.[0-9]+) yylval.number = atof(yytext); return NUMBER;
default yylval.string = NULL; return TOK_DEFAULT;
[a-z0-9][a-z0-9_]* yylval.string = strdup(yytext); return TOKEN;
"{" parens = 0; str_buf_head = str_buf; *str_buf_head++ = '{'; BEGIN(s_code);
\" str_buf_head = str_buf; bronze = 0; BEGIN(s_string);
}
<INITIAL,s_code>{
"//".*\n
"/*" caller = YY_START; BEGIN(s_comment);
}
<s_comment>{
[^*]+
"*"+[^*/]*
"*"+"/" BEGIN(caller);
}
<s_code>{
\" bronze = 0; BEGIN(s_code_string);
[^"{}]* bronze = 0; str_buf_head = qccpy(str_buf_head, yytext);
"{" *str_buf_head++ = '{'; parens++;
"}" {
*str_buf_head++ = '}';
if (!parens--) {
*str_buf_head = '\0';
yylval.string = strdup(str_buf);
BEGIN(INITIAL);
return CODE;
}
}
}
<s_code_string>{
\\. str_buf_head = qccpy(str_buf_head, yytext);
[^"]* str_buf_head = qccpy(str_buf_head, yytext);
\" BEGIN(s_code);
}
<s_string>{
\\b bronze = !bronze;
\\\{[0-9]{1,3}\} *str_buf_head++ = atoi(yytext+2);
\\\[ *str_buf_head++ = 0x10;
\\\] *str_buf_head++ = 0x11;
\\\. *str_buf_head++ = bronze?(0x1C|0x80):0x1C;
\\< *str_buf_head++ = 29;
\\- *str_buf_head++ = 30;
\\> *str_buf_head++ = 31;
\\\( *str_buf_head++ = 128;
\\= *str_buf_head++ = 129;
\\\) *str_buf_head++ = 130;
\\. *str_buf_head++ = bronze?(yytext[1]^0x80):yytext[1];
[^"\\]* str_buf_head = qccpy(str_buf_head, yytext);
\" {
*str_buf_head = '\0';
yylval.string = strdup(str_buf);
BEGIN(INITIAL);
return STRING;
}
}
[ \t]*
(.|\n) return *yytext;
<*><<EOF>> return 0;
%%
static char *qccpy(char *buffer, const char *str) {
while (*str) {
if (bronze && (*str & ~0x80) > 32) *buffer++ = *str++ ^ 0x80;
else *buffer++ = *str++;
}
*buffer = '\0';
return buffer;
}
static char *bronzize(const char *str, int bronzetype) {
static char *ret = NULL;
char *tmp;
if (ret) free(ret);
tmp = ret = strdup(str);
switch (bronzetype) {
case -1:
while (*tmp) {
if ((*tmp & ~0x80) > 32) *tmp++ &= ~0x80;
else tmp++;
}
break;
case 0:
while (*tmp) {
if ((*tmp & ~0x80) > 32) *tmp++ ^= 0x80;
else tmp++;
}
break;
case 1:
while (*tmp) {
if ((*tmp & ~0x80) > 32) *tmp++ |= 0x80;
else tmp++;
}
break;
}
return ret;
}
yywrap() { return 1; }
static void writewrites(const char *str) {
signed short shrt;
while (str[0] && str[1]) {
shrt = (str[0]&0xff) | (str[1] << 8);
printf("\t\tWriteShort(MSG_ONE, %d);\n", shrt);
str += 2;
}
if (*str)
printf("\t\tWriteByte(MSG_ONE, %d);\n", (unsigned char)*str);
}
struct {
const char *func_name;
const char *def, *disabled, *selected, *unmangled;
} func_names[4096];
static char func_names_count = 0;
static int mungefunc(struct menu_entry *e, const char *def, const char *disabled, const char *selected, const char *unmangled) {
int i, j;
char *func1 = NULL, *func2 = NULL;
do_over:
for (i = 0; i < func_names_count; i++) {
if ((func_names[i].def && !strcmp(func_names[i].def, def))
&& ((!disabled && !func_names[i].disabled) || !strcmp(func_names[i].disabled, disabled))
&& ((!selected && !func_names[i].selected) || !strcmp(func_names[i].selected, selected))
&& ((!unmangled && !func_names[i].unmangled) || !strcmp(func_names[i].unmangled, unmangled))) {
e->func_name = (char*)func_names[i].func_name;
return 0;
}
if (!strcmp(func_names[i].func_name, e->func_name)) {
if (!func1) {
j = 2;
func1 = e->func_name;
func2 = malloc(strlen(e->func_name) + 10 + 1);
e->func_name = func2;
}
sprintf(func2, "%s%d", func1, j);
j++;
goto do_over;
}
}
func_names[i].func_name = e->func_name;
func_names[i].def = strdup(def);
func_names[i].disabled = disabled?strdup(disabled):NULL;
func_names[i].selected = selected?strdup(selected):NULL;
func_names[i].unmangled = unmangled?strdup(unmangled):NULL;
func_names_count++;
return 1;
}
static int writefunc(struct menu_entry *e, const char *def, const char *disabled, const char *selected, const char *unmangled) {
if (!mungefunc(e, def, disabled, selected, unmangled)) return 0;
printf("void(float type) %s = {\n", e->func_name);
if (disabled || selected || unmangled)
printf("\tif (type == K_DEFAULT) {\n");
writewrites(def);
if (disabled) {
printf("\t} else if (type == K_DISABLED) {\n");
writewrites(disabled);
}
if (selected) {
printf("\t} else if (type == K_SELECTED) {\n");
writewrites(selected);
}
if (unmangled) {
printf("\t} else if (type == K_UNMANGLED) {\n");
writewrites(unmangled);
}
if (disabled || selected || unmangled)
printf("\t}\n");
printf("}\n\n");
return 1;
}
static const char default_activate_code[] =
"{\n"
"\t\tstatus = k_weapon_toggle(self, %1$s, %2$s);\n"
"\t\tif (status == FALSE) bs = k_menup_sold_;\n"
"\t\telse if (status == TRUE) bs = k_menup_bought_;\n"
"\t\telse if (status == -1) bs = k_menup_can_t_afford_;\n"
"\t\tselected = %3$s;\n"
"\t}"
;
static const char default_strings_code[] =
"{\n"
"\tif (k_weapon_query(self, %1$s)) return K_SELECTED;\n"
"\n"
"\treturn K_DEFAULT;\n"
"}"
;
int main(int argc, char *argv[]) {
unsigned int i, j;
unsigned int runwidth, thiswidth;
unsigned int bit = 0;
char buffer[4096];
yydebug = 0;
printf("/* This file was automatically generated by menusmarf */\n\n");
func_names[0].func_name = "k_menup_begin";
func_names[0].def = NULL;
func_names_count++;
printf( "void() k_menup_begin = {\n"
"\tmsg_entity = self;\n"
"\tWriteByte(MSG_ONE, SVC_CENTERPRINT);\n"
"}\n\n");
func_names[1].func_name = "k_menup_end";
func_names[1].def = NULL;
func_names_count++;
printf( "void() k_menup_end = {\n"
"\tWriteByte(MSG_ONE, 0);\n"
"}\n\n");
{
struct menu_entry decor[] = {
{ func_name: "k_menup_entry_begin" },
{ func_name: "k_menup_entry_end" },
{ func_name: "k_menup_bought_" },
{ func_name: "k_menup_sold_" },
{ func_name: "k_menup_points__" },
{ func_name: "k_menup_can_t_afford_" },
};
writefunc(&decor[0], "\20 ", bronzize("[ ", 1), "\20 \274", NULL);
writefunc(&decor[1], " \21\n", bronzize(" ]\n", 1), "\276 \21\n", NULL);
writefunc(&decor[2], bronzize("Bought ", 1), NULL, NULL, NULL);
writefunc(&decor[3], bronzize("Sold ", 1), NULL, NULL, NULL);
writefunc(&decor[4], "Points\272 ", NULL, NULL, NULL);
writefunc(&decor[5], bronzize("Can't afford ", 1), NULL, NULL, NULL);
}
while (!yyparse() && menu_name) {
for (i = 0; i < menu_entries_count; i++) {
runwidth = 0;
for (j = i; menu_entries[j].type == menu_entries[i].type; j++) {
switch (menu_entries[j].type) {
case 0:
continue; /* Don't need to pad. */
case 1:
thiswidth = strlen(menu_entries[j].name);
break;
case 2:
thiswidth = strlen(menu_entries[j].name);
break;
}
if (thiswidth > runwidth)
runwidth = thiswidth;
}
for (j = i; menu_entries[j].type == menu_entries[i].type; j++) {
switch (menu_entries[j].type) {
case 0:
/* Don't need to pad. */
snprintf(buffer, sizeof(buffer), "%s\n", menu_entries[j].name);
writefunc(&menu_entries[j], buffer, NULL, NULL, NULL);
menu_entries[j].bit = -1;
break;
case 1:
snprintf(buffer, sizeof(buffer), "%d. %-*s", menu_entries[j].impulse%10, runwidth, menu_entries[j].name);
writefunc(&menu_entries[j], buffer, bronzize(buffer, 1), NULL, NULL);
menu_entries[j].bit = -1;
break;
case 2:
printf("float %-30s = %d;\n", menu_entries[j].number_name, bit);
printf("float %-30s = %.0f;\n", menu_entries[j].price_name, menu_entries[j].price);
snprintf(buffer, sizeof(buffer), "%d\256 %-*s \234\34\234%6.0f", menu_entries[j].impulse%10, runwidth, menu_entries[j].name, menu_entries[j].price);
writefunc(&menu_entries[j], buffer, bronzize(buffer, 1), buffer, menu_entries[j].name);
menu_entries[j].bit = bit++;
break;
}
}
i = j-1;
}
for (i = 0; i < menu_entries_count; i++) {
if (menu_entries[i].bit != -1 && !menu_entries[i].code_strings)
menu_entries[i].code_strings = (char*)default_strings_code;
if (menu_entries[i].code_strings) {
printf("float() %s_%d = ", menu_name, i);
printf(menu_entries[i].code_strings,
menu_entries[i].number_name,
menu_entries[i].price_name,
menu_entries[i].func_name,
menu_entries[i].name,
menu_entries[i].impulse);
printf(";\n\n");
}
}
printf( "float() %s = {\n"
"\tlocal float status, nomenu;\n"
"\tlocal void() bs;\n"
"\tlocal void(float type) selected;\n"
"\n"
"\tnomenu = 0;\n"
"\tbs = SUB_Null;\n"
"\tselected = SUB_Null;\n"
"\n", menu_name);
for (i = 0; i < menu_entries_count; i++) {
if (menu_entries[i].impulse) {
printf("\tif (self.impulse == %d) ", menu_entries[i].impulse);
snprintf(buffer, sizeof(buffer), default_activate_code,
menu_entries[i].number_name,
menu_entries[i].price_name,
menu_entries[i].func_name,
menu_entries[i].name,
menu_entries[i].impulse);
if (menu_entries[i].code_activate)
printf(menu_entries[i].code_activate,
menu_entries[i].number_name,
menu_entries[i].price_name,
menu_entries[i].func_name,
menu_entries[i].name,
menu_entries[i].impulse,
buffer);
else
printf("%s", buffer);
printf("\n");
}
}
printf( "\n"
"\tif (nomenu || (!self.impulse && time < self.menu_time)) { self.impulse = 0; return TRUE; }\n"
"\tself.menu_time = time + 1.4;\n"
"\n"
"\tself.impulse = 0;\n"
"\n"
"\tk_menup_begin();\n");
for (i = 0; i < menu_entries_count; i++) {
if (menu_entries[i].code_strings)
printf( "\tstatus = %s_%d();\n"
"%s"
"\t%s(status);\n"
"%s",
menu_name, i,
menu_entries[i].type?"\tk_menup_entry_begin(status);\n":"",
menu_entries[i].func_name,
menu_entries[i].type?"\tk_menup_entry_end(status);\n":"");
else
printf( "%s"
"\t%s(K_DEFAULT);\n"
"%s",
menu_entries[i].type?"\tk_menup_entry_begin(K_DEFAULT);\n":"",
menu_entries[i].func_name,
menu_entries[i].type?"\tk_menup_entry_end(K_DEFAULT);\n":"");
}
printf( "\tk_menu_status();\n"
"\tif (bs != SUB_Null) {\n"
"\t\tbs();\n"
"\t\tselected(K_UNMANGLED);\n"
"\t} else\n"
"\t\tWriteByte(MSG_ONE, 10);\n"
"\tk_menup_end();\n"
"\n"
"\treturn TRUE;"
"\n"
"}\n\n");
}
}

145
klik/unused/menusmarf.y Normal file
View file

@ -0,0 +1,145 @@
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define YYDEBUG 1
struct menu_entry {
char *name;
int impulse, bit;
char *func_name;
char *number_name;
float price;
char *price_name;
char *code_activate;
char *code_strings;
unsigned int type;
};
#define MAX_MENU_ENTRIES 4096
struct menu_entry menu_entries[MAX_MENU_ENTRIES];
int menu_entries_count = 0;
char *menu_name = NULL;
static char *gen_funcname(const char *str);
static char *gen_numbername(const char *str);
static char *gen_pricename(const char *str);
%}
%union {
char *string;
char *code;
float number;
struct menu_entry *entry;
}
%token STRING NUMBER TOK_DEFAULT CODE TOKEN
%type <string> STRING TOKEN
%type <number> NUMBER
%type <code> TOK_DEFAULT CODE code
%type <entry> entry
%%
file: /* empty */ { menu_name = NULL; }
| { menu_entries_count = 0; } TOKEN '\n' menu_entries { menu_name = $2; YYACCEPT; }
;
menu_entries: exp_entry {}
| menu_entries exp_entry {}
;
exp_entry: entry { $1->impulse = 0; }
| NUMBER entry { $2->impulse = $1; }
;
entry: STRING code code '\n' {
if (menu_entries_count >= MAX_MENU_ENTRIES) YYERROR;
memset(&menu_entries[menu_entries_count], 0, sizeof(*menu_entries));
menu_entries[menu_entries_count].name = $1;
menu_entries[menu_entries_count].func_name = gen_funcname($1);
menu_entries[menu_entries_count].code_activate = $2;
menu_entries[menu_entries_count].code_strings = $3;
menu_entries[menu_entries_count].type = $2?1:0;
$$ = &menu_entries[menu_entries_count];
menu_entries_count++;
}
| STRING NUMBER code code '\n' {
if (menu_entries_count >= MAX_MENU_ENTRIES) YYERROR;
memset(&menu_entries[menu_entries_count], 0, sizeof(*menu_entries));
menu_entries[menu_entries_count].name = $1;
menu_entries[menu_entries_count].func_name = gen_funcname($1);
menu_entries[menu_entries_count].number_name = gen_numbername($1);
menu_entries[menu_entries_count].price = $2;
menu_entries[menu_entries_count].price_name = gen_pricename($1);
menu_entries[menu_entries_count].code_activate = $3;
menu_entries[menu_entries_count].code_strings = $4;
menu_entries[menu_entries_count].type = 2;
$$ = &menu_entries[menu_entries_count];
menu_entries_count++;
}
;
code: /* empty */ { $$ = NULL; }
| TOK_DEFAULT
| CODE
;
%%
static char *gen_funcname(const char *str) {
char *ret, *t, ch;
ret = malloc(strlen(str) + 8 + 1);
strcpy(ret, "k_menup_");
for (t = ret + 8; *str; t++, str++) {
ch = *str & ~0x80;
if (ch >= 'A' && ch <= 'Z')
*t = ch | 0x20;
else if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'))
*t = ch;
else
*t = '_';
}
*t = '\0';
return ret;
}
static char *gen_numbername(const char *str) {
char *ret, *t, ch;
ret = malloc(strlen(str) + 2 + 6/* for _PRICE */ + 1);
strcpy(ret, "K_");
for (t = ret + 2; *str; t++, str++) {
ch = *str & ~0x80;
if (ch >= 'a' && ch <= 'z')
*t = ch & ~0x20;
else if ((ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))
*t = ch;
else
*t = '_';
}
*t = '\0';
return ret;
}
static char *gen_pricename(const char *str) {
char *ret;
ret = gen_numbername(str);
strcat(ret, "_PRICE");
return ret;
}
yyerror(char *s) {
fprintf(stderr, "Parse error 000D!\n");
exit(-1);
}

162
klik/unused/physics.qc Normal file
View file

@ -0,0 +1,162 @@
/* THIS DOES NOT WORK. */
/* If you want to try it, give something
MOVETYPE_FLY and SOLID_BBOX
touch = physics_touch_bounce;
think = physics_think_float;
nextthink = time + 0.1 */
float PHYSICS_ACCEL = 30;
float PHYSICS_EPSILON = -8;
float STOP_EPSILON = 0.1;
void() physics_touch_bounce = {
local vector dir;
local float backoff;
if (!util_solid(other))
return;
if (other.mass && self.mass && (other.mass < self.mass)) {
local float d;
d = other.mass / self.mass;
self.velocity = self.velocity + d*other.velocity;
} else {
self.velocity = self.velocity + other.velocity;
}
/* Ripped from sv_phys.c, loosely */
dir = normalize(self.velocity);
traceline(self.origin - dir, self.origin + dir, FALSE, self);
backoff = dir * trace_plane_normal;
backoff = backoff * 1.5;
dir = trace_plane_normal * backoff;
self.velocity = self.velocity - dir;
};
vector(vector start, vector dir) _dist_to_boundary = {
local vector hi, lo, mid, lmid;
lo = start;
hi = start + dir;
mid = lo;
do {
lmid = mid;
mid = (lo + hi) * 0.5;
if (pointcontents(mid) == CONTENT_EMPTY)
hi = mid;
else
lo = mid;
} while (vlen(mid - lmid) > 1.0);
return mid - start;
};
void() physics_think_float = {
local vector mid;
local float contents, liquid_bottom, liquid_middle;
local float spd, mxspd;
if (self.mdl_think) {
if (!self.mdl_thought) self.mdl_think();
self.mdl_thought = FALSE;
}
mxspd = sv_maxspeed * 0.7 * 0.75;
mid = self.origin + (self.maxs + self.mins) * 0.5;
contents = pointcontents(self.origin);
if (contents >= CONTENT_LAVA && contents <= CONTENT_WATER)
liquid_middle = TRUE;
else liquid_middle = FALSE;
mid_z = self.origin_z + self.mins_z;
contents = pointcontents(self.origin);
if (contents >= CONTENT_LAVA && contents <= CONTENT_WATER)
liquid_bottom = TRUE;
else liquid_bottom = FALSE;
if (self.flags & FL_ONGROUND) {
if (self.velocity_z < 0)
self.velocity_z = 0 - self.velocity_z;
}
/* Friction */
spd = vlen(self.velocity);
if (spd > 0) {
self.velocity = self.velocity * (1/spd);
if (self.flags & FL_ONGROUND) spd = spd - sv_friction*0.1;
else if (liquid_bottom) spd = spd - 3*sv_waterfriction*0.1;
if (spd <= 0) self.velocity = '0 0 0';
else self.velocity = self.velocity * spd;
}
/* "Gravity" */
if (liquid_middle) {
if (!(self.flags & FL_INWATER)) {
if (self.velocity_z < 0 && self.velocity_z >= PHYSICS_EPSILON) {
self.flags = self.flags | FL_JUMPRELEASED;
self.velocity_z = 0;
}
self.flags = self.flags | FL_INWATER;
if (self.velocity_z < 0)
self.velocity = self.velocity * 0.07;
} else if (self.velocity_z && (self.flags & FL_JUMPRELEASED)) {
self.flags = self.flags - FL_JUMPRELEASED;
}
if (!(self.flags & FL_JUMPRELEASED)) {
mid = self.origin + (self.maxs + self.mins) * 0.5;
if (pointcontents(mid + self.velocity) == CONTENT_EMPTY) {
mid = _dist_to_boundary(mid, self.velocity);
self.velocity_z = mid_z + self.velocity_z*0.02;
} else {
spd = self.velocity_z + PHYSICS_ACCEL * 0.1;
if (fabs(spd) <= mxspd || self.velocity_z < 0)
self.velocity_z = spd;
}
}
} else {
if (!liquid_bottom) {
self.velocity_z = self.velocity_z - sv_gravity*0.1;
if (self.flags & FL_INWATER)
self.flags = self.flags - FL_INWATER;
}
if (self.flags & FL_INWATER) {
mid = self.origin + (self.maxs + self.mins) * 0.5;
if (pointcontents(mid + self.velocity) == CONTENT_EMPTY) {
mid = _dist_to_boundary(mid, self.velocity);
self.velocity_z = mid_z + self.velocity_z*0.02;
} else {
spd = self.velocity_z - PHYSICS_ACCEL * 0.1;
if (fabs(spd) <= mxspd || self.velocity_z > 0)
self.velocity_z = spd;
}
} else {
spd = self.velocity_z - PHYSICS_ACCEL * 0.1;
if (fabs(spd) <= mxspd || self.velocity_z > 0)
self.velocity_z = spd;
}
}
if (self.velocity_x > (0 - STOP_EPSILON) && self.velocity_x < STOP_EPSILON)
self.velocity_x = 0;
if (self.velocity_y > (0 - STOP_EPSILON) && self.velocity_y < STOP_EPSILON)
self.velocity_y = 0;
if (self.velocity_z > (0 - STOP_EPSILON) && self.velocity_z < STOP_EPSILON)
self.velocity_z = 0;
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
/* should use sv_mintic, but mdl_think runs at 10Hz */
self.nextthink = time + 0.1;
};

2
klik/unused/physics.qh Normal file
View file

@ -0,0 +1,2 @@
void() physics_touch_bounce;
void() physics_think_float;

105
klik/weapons/w_axe.qc Normal file
View file

@ -0,0 +1,105 @@
#include "common.qh"
#include "weapon.qh"
#include "damage.qh"
#include "effect.qh"
void() _w_axe_deathmsg = {
local float r;
local string att_nname, def_nname;
r = random();
def_nname = name(self);
att_nname = name(self.dmg_attacker);
if (r < 0.25) bprint(PRINT_DEATH, def_nname, " gets chopped down to size by ", att_nname, ".\n");
else if (r < 0.5) bprint(PRINT_DEATH, att_nname, " mames ", def_nname, " with a rusty axe.\n");
else if (r < 0.75) bprint(PRINT_DEATH, def_nname, " loses his scalp to ", att_nname, ".\n");
else bprint(PRINT_DEATH, att_nname, "'s axe penetrates ", def_nname, " straight to the bone.\n");
};
void() _w_axe_fire =
{
local vector source;
source = shootorigin(self);
makevectors (self.v_angle);
traceline (source, source + v_forward*64, FALSE, self);
if (trace_fraction == 1.0)
return;
ghost_inflictor.classname = "AXE";
ghost_inflictor.dmg = 20;
ghost_inflictor.mass = ghost_inflictor.mass * 8;
ghost_inflictor.velocity = v_forward*1000;
damage_attack(ghost_inflictor);
if (!damage(trace_ent, self, ghost_inflictor, ghost_inflictor.dmg, _w_axe_deathmsg)) {
/* We hit the world. */
sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
effect_gun_spark(trace_endpos, v_forward * 250, 3);
}
};
void() _w_axe_think_1 = {
self.weaponframe = self.weaponframe + 1;
if (self.weaponframe == 3)
_w_axe_fire();
if (self.weaponframe <= 1 || self.weaponframe > 4) {
self.weaponframe = 0;
self.w_think = NOTHING_function;
}
};
void() _w_axe_think_2 = {
self.weaponframe = self.weaponframe + 1;
if (self.weaponframe == 7)
_w_axe_fire();
if (self.weaponframe <= 5 || self.weaponframe > 8) {
self.weaponframe = 0;
self.w_think = NOTHING_function;
}
};
/* WEAPON 1 axe */
float(float action)
w_axe = {
if (action == WEAPON_AMMO) {
return 0;
} else if (action == WEAPON_WEIGHT) {
return 1;
} else if (action == WEAPON_SELECTABLE) {
return TRUE;
} else if (action == WEAPON_FIRE) {
self.attack_finished = time + 0.5;
sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
if (random() < 0.5) {
self.weaponframe = 1;
self.w_think = _w_axe_think_1;
} else {
self.weaponframe = 5;
self.w_think = _w_axe_think_2;
}
self.w_thought = TRUE;
self.mdl_func(MDL_FUNC_FIRE, 0);
} else if (action == WEAPON_SELECT) {
self.weaponmodel = "progs/v_axe.mdl";
self.weaponframe = 0;
self.mdl_mod = (self.mdl_mod & ~MDL_MOD_WEP_MASK) | MDL_MOD_WEP_AXE;
weaponprint("Axe");
} else if (action == WEAPON_INIT) {
precache_model("progs/v_axe.mdl");
precache_sound("player/axhit1.wav");
precache_sound("player/axhit2.wav");
precache_sound("weapons/ax1.wav");
}
return 0;
};

View file

@ -0,0 +1,143 @@
#include "common.qh"
#include "weapon.qh"
#include "equip.qh"
#include "damage.qh"
#include "misc.qh"
#include "effect.qh"
#define STR_EQUIPID_GRENADE_LAUNCHER "Grenade Launcher"
void() _deathmsg_grenade_launcher = {
local string def_nname, att_nname;
local float r;
def_nname = name(self);
att_nname = name(self.dmg_attacker);
if (self == self.dmg_attacker) {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " tries to put the pin back in.\n");
else bprint(PRINT_DEATH, def_nname, " launches the pin.\n");
} else {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " eats ", att_nname, "'s pineapple.\n");
else bprint(PRINT_DEATH, att_nname, "'s pineapple blows ", def_nname, " across the level.\n");
}
};
void() _grenade_explode = {
local float contents;
contents = pointcontents(self.origin);
if (contents >= CONTENT_LAVA && contents <= CONTENT_WATER) {
self.dmg *= 0.9;
self.lip *= 0.8;
self.mass *= 1.5;
self.speed *= 0.8;
}
self.velocity = '0 0 0';
damage_radius(world, self.goalentity, self, _deathmsg_grenade_launcher);
effect_explosion(self.origin);
safe_remove(self);
};
void() _grenade_touch =
{
if (other.takedamage != DAMAGE_AIM) {
sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
return;
}
if (pointcontents(self.origin) == CONTENT_SKY) {
remove(self);
return;
}
_grenade_explode();
};
void() _w_grenade_launcher_think = {
self.weaponframe++;
if (self.weaponframe < 1 || self.weaponframe > 6) {
self.w_think = NOTHING_function;
self.weaponframe = 0;
}
};
void() _w_grenade_launcher_fire = {
local vector dir;
local entity missile;
if (!util_weapon_use_ammo(ammo_rockets, 1))
return;
sound(self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
makevectors(self.v_angle);
dir = v_forward*600 + v_up*200 + crandom()*v_right*10 + crandom()*v_up*10;
missile = spawn_missile("PINEAPPLE", "progs/grenade.mdl", shootorigin(self), dir, 1);
missile.movetype = MOVETYPE_BOUNCE;
missile.avelocity_x = crandom()*360;
missile.avelocity_y = crandom()*360;
missile.avelocity_z = crandom()*360;
missile.dmg = 120;
missile.mass = missile.dmg * 8;
missile.lip = missile.dmg;
missile.speed = 800;
missile.touch = _grenade_touch;
missile.think = _grenade_explode;
missile.nextthink = time + 2.5;
damage_attack(missile);
self.weaponframe = 1;
self.w_think = _w_grenade_launcher_think;
self.mdl_func(MDL_FUNC_FIRE, 0);
effect_smallkick(self);
self.attack_finished = time + 0.6;
};
/* WEAPON 6 grenade_launcher */
float(float action)
w_grenade_launcher = {
if (action == WEAPON_AMMO) {
self.items |= IT_ROCKETS;
return self.ammo_rockets;
} else if (action == WEAPON_WEIGHT) {
return 50;
} else if (action == WEAPON_SELECTABLE) {
if (!equip_query(self, EQUIPID_GRENADE_LAUNCHER))
return 0;
if (self.ammo_rockets >= 1)
return 1;
return -1;
} else if (action == WEAPON_SELECT) {
self.weaponmodel = "progs/v_rock.mdl";
self.weaponframe = 0;
self.mdl_mod = (self.mdl_mod & ~MDL_MOD_WEP_MASK) | MDL_MOD_WEP_GRENADE_LAUNCHER;
weaponprint(STR_EQUIPID_GRENADE_LAUNCHER);
} else if (action == WEAPON_FIRE) {
_w_grenade_launcher_fire();
} else if (action == WEAPON_INIT) {
precache_model("progs/v_rock.mdl");
precache_model("progs/grenade.mdl");
precache_sound("weapons/grenade.wav");
precache_sound("weapons/bounce.wav");
}
return 0;
};

View file

@ -0,0 +1,228 @@
#include "common.qh"
#include "weapon.qh"
#include "equip.qh"
#include "damage.qh"
#include "misc.qh"
#include "effect.qh"
#define STR_EQUIPID_LIGHTNING_GUN "Lightning Gun"
void() _deathmsg_shaft = {
local string def_name, att_name;
local float r;
def_name = name(self);
att_name = name(self.dmg_attacker);
r = random()*4;
if (r < 1) bprint(PRINT_DEATH, def_name, " accepts ", att_name, "'s shaft.\n");
else if (r < 2) bprint(PRINT_DEATH, att_name, " gives ", def_name, " the shaft.\n");
else if (r < 3) bprint(PRINT_DEATH, def_name, " got smitten by ", att_name, ".\n");
else bprint(PRINT_DEATH, att_name, " fries up some ", def_name, " bacon.\n");
};
void() _deathmsg_discharge = {
local string def_name, att_name;
local float r;
def_name = name(self);
att_name = name(self.dmg_attacker);
if (self.dmg_attacker == self) {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_name, " conducts electricity.\n");
else bprint(PRINT_DEATH, def_name, " tries to become a lightbulb.\n");
} else {
r = random()*3;
if (r < 1) bprint(PRINT_DEATH, def_name, " accepts ", att_name, "'s discharge.\n");
else if (r < 2) bprint(PRINT_DEATH, att_name, " sends ", def_name, " a jolt.\n");
else bprint(PRINT_DEATH, def_name, " conducts electricity with ", att_name, ".\n");
}
};
void(vector p1, vector p2, float d) _w_lightning_gun_trace_damage =
{
local entity e1, e2;
local vector f;
f = p2 - p1;
f = normalize (f);
f_y = f_x = -f_y;
f_z = 0;
f = f*16;
e1 = e2 = world;
ghost_inflictor.classname = "LIGHTNING";
ghost_inflictor.dmg = d;
ghost_inflictor.mass = ghost_inflictor.dmg * 8;
ghost_inflictor.velocity = v_forward * 1000;
damage_attack(ghost_inflictor);
traceline (p1, p2, FALSE, self);
e1 = trace_ent;
damage(trace_ent, self, ghost_inflictor, ghost_inflictor.dmg, _deathmsg_shaft);
traceline (p1 + f, p2 + f, FALSE, self);
e2 = trace_ent;
if (trace_ent != e1)
damage(trace_ent, self, ghost_inflictor, ghost_inflictor.dmg, _deathmsg_shaft);
traceline (p1 - f, p2 - f, FALSE, self);
if (trace_ent != e1 && trace_ent != e2)
damage(trace_ent, self, ghost_inflictor, ghost_inflictor.dmg, _deathmsg_shaft);
};
void(entity ignore, entity attacker, entity inflictor, void() deathmessage)
damage_radius_lightning = {
local entity head;
local vector iorg, org;
local float points;
local float d, m, r;
local float cont;
d = inflictor.dmg;
m = inflictor.mass;
r = inflictor.lip;
iorg = center(inflictor);
for (head = findradius(iorg, r + 40); head; head = head.chain) {
if (head == ignore)
continue;
if (!_damage_radius_can_hit(iorg, head))
continue;
cont = pointcontents(trace_endpos);
if (cont < CONTENT_LAVA || cont > CONTENT_WATER)
continue;
org = center(head);
points = r - (0.5 * vlen(iorg - org));
if (points <= 0)
continue;
inflictor.dmg = (points * d) / r;
inflictor.mass = (points * m) / r;
damage(head, attacker, inflictor, inflictor.dmg, deathmessage);
}
};
void() _w_lightning_gun_beam =
{
local vector org;
local float cells;
org = shootorigin(self);
// explode if under water
if (self.waterlevel > 1)
{
self.mdl_func(MDL_FUNC_IDLE, 0);
cells = self.ammo_cells;
self.ammo_cells = 0;
ghost_inflictor.classname = "DISCHARGE";
ghost_inflictor.origin = self.origin;
ghost_inflictor.velocity = '0 0 0';
ghost_inflictor.dmg = 35*cells;
ghost_inflictor.mass = ghost_inflictor.dmg * 8;
ghost_inflictor.lip = ghost_inflictor.dmg;
ghost_inflictor.speed = 1000;
damage_radius_lightning(world, self, ghost_inflictor, _deathmsg_discharge);
return;
}
if (self.t_width < time) {
sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
self.t_width = time + 0.6;
}
makevectors(self.v_angle);
traceline (org, org + v_forward*600, TRUE, self);
effect_lightning2(self, org, trace_endpos);
effect_smallkick(self);
_w_lightning_gun_trace_damage(self.origin, trace_endpos, 30);
};
//============================================================================
void() _w_lightning_gun_think = {
self.weaponframe++;
if (self.weaponframe == 5)
self.weaponframe = 1;
/* FIXME: Use short circuit logic here when compiler supports */
if (!self.button0 || self.impulse || self.weaponframe < 1 || self.weaponframe > 5) {
self.weaponframe = 0;
self.w_think = NOTHING_function;
self.mdl_func(MDL_FUNC_IDLE, 0);
return;
}
if (!util_weapon_use_ammo(ammo_cells, 1)) {
self.weaponframe = 0;
self.w_think = NOTHING_function;
self.mdl_func(MDL_FUNC_IDLE, 0);
return;
}
_w_lightning_gun_beam();
self.attack_finished = time + 0.2;
};
/* WEAPON 8 lightning_gun */
float(float action)
w_lightning_gun = {
if (action == WEAPON_AMMO) {
self.items |= IT_CELLS;
return self.ammo_cells;
} else if (action == WEAPON_WEIGHT) {
local vector point;
local float cont;
point = self.origin;
point_z = self.origin_z + (self.mins_z + self.maxs_z) * 0.5;
cont = pointcontents(point);
if (cont >= CONTENT_LAVA && cont <= CONTENT_WATER)
return -60;
return 60;
} else if (action == WEAPON_SELECTABLE) {
if (!equip_query(self, EQUIPID_LIGHTNING_GUN))
return 0;
if (self.ammo_cells >= 1)
return 1;
return -1;
} else if (action == WEAPON_SELECT) {
self.weaponmodel = "progs/v_light.mdl";
self.weaponframe = 0;
self.mdl_mod = (self.mdl_mod & ~MDL_MOD_WEP_MASK) | MDL_MOD_WEP_LIGHTNING_GUN;
weaponprint(STR_EQUIPID_LIGHTNING_GUN);
} else if (action == WEAPON_FIRE) {
sound(self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
self.w_think = _w_lightning_gun_think;
self.w_think();
self.w_thought = TRUE;
} else if (action == WEAPON_INIT) {
precache_model("progs/v_light.mdl");
precache_sound("weapons/lstart.wav");
precache_sound("weapons/lhit.wav");
}
return 0;
};

187
klik/weapons/w_nailgun.qc Normal file
View file

@ -0,0 +1,187 @@
#include "common.qh"
#include "weapon.qh"
#include "equip.qh"
#include "damage.qh"
#include "misc.qh"
#define STR_EQUIPID_NAILGUN "Nailgun"
void() _deathmsg_nailgun = {
local string def_nname, att_nname;
local float r;
def_nname = name(self);
att_nname = name(self.dmg_attacker);
if (self.dmg_attacker == self) {
bprint(PRINT_DEATH, def_nname, " enjoys the pain.\n");
} else {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " was nailed by ", att_nname, ".\n");
else bprint(PRINT_DEATH, att_nname, " nailed ", def_nname, ".\n");
}
};
void() _spike_touch =
{
if (pointcontents(self.origin) == CONTENT_SKY) {
remove(self);
return;
}
if (!damage(other, self.goalentity, self, self.dmg, _deathmsg_nailgun))
effect_nail_spark(self.origin, self.velocity);
safe_remove(self);
};
void(float ox, float damg, string mod) _nailgun_fire_spike =
{
local vector dir;
local entity missile;
makevectors (self.v_angle);
dir = aim(self, 1000);
missile = spawn_missile("NAIL", mod, shootorigin(self) + v_right*ox, dir, 1000);
missile.dmg = damg;
missile.mass = missile.dmg * 8;
missile.touch = _spike_touch;
damage_attack(missile);
effect_muzzleflash();
effect_smallkick(self);
};
//============================================================================
void() _w_nailgun_think = {
self.weaponframe++;
if (self.weaponframe == 9)
self.weaponframe = 1;
/* FIXME: Use short circuit logic here when compiler supports */
if (!self.button0 || self.weaponframe < 1 || self.weaponframe > 8) {
self.weaponframe = 0;
self.w_think = NOTHING_function;
self.mdl_func(MDL_FUNC_IDLE, 0);
return;
}
if (!util_weapon_use_ammo(ammo_nails, 1)) {
self.weaponframe = 0;
self.w_think = NOTHING_function;
self.mdl_func(MDL_FUNC_IDLE, 0);
return;
}
sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
if (self.weaponframe & 1) _nailgun_fire_spike(4, 9, "progs/spike.mdl");
else _nailgun_fire_spike(-4, 9, "progs/spike.mdl");
self.attack_finished = time + 0.2;
};
/* WEAPON 4 nailgun */
float(float action)
w_nailgun = {
if (action == WEAPON_AMMO) {
self.items |= IT_NAILS;
return self.ammo_nails;
} else if (action == WEAPON_WEIGHT) {
return 30;
} else if (action == WEAPON_SELECTABLE) {
if (!equip_query(self, EQUIPID_NAILGUN))
return 0;
if (self.ammo_nails >= 1)
return 1;
return -1;
} else if (action == WEAPON_SELECT) {
self.weaponmodel = "progs/v_nail.mdl";
self.weaponframe = 0;
self.mdl_mod = (self.mdl_mod & ~MDL_MOD_WEP_MASK) | MDL_MOD_WEP_NAILGUN;
weaponprint(STR_EQUIPID_NAILGUN);
} else if (action == WEAPON_FIRE) {
self.mdl_func(MDL_FUNC_FIRE, 0);
self.w_think = _w_nailgun_think;
self.w_think();
self.w_thought = TRUE;
} else if (action == WEAPON_INIT) {
precache_model("progs/v_nail.mdl");
precache_model("progs/spike.mdl");
precache_sound("weapons/rocket1i.wav");
}
return 0;
};
//============================================================================
#define STR_EQUIPID_SUPER_NAILGUN "Super Nailgun"
void() _w_super_nailgun_think = {
self.weaponframe++;
if (self.weaponframe == 9)
self.weaponframe = 1;
/* FIXME: Use short circuit logic here when compiler supports */
if (!self.button0 || self.weaponframe < 1 || self.weaponframe > 8) {
self.weaponframe = 0;
self.w_think = NOTHING_function;
self.mdl_func(MDL_FUNC_IDLE, 0);
return;
}
if (!util_weapon_use_ammo(ammo_nails, 2)) {
self.weaponframe = 0;
self.w_think = NOTHING_function;
self.mdl_func(MDL_FUNC_IDLE, 0);
return;
}
sound(self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
_nailgun_fire_spike(0, 18, "progs/s_spike.mdl");
self.attack_finished = time + 0.2;
};
/* WEAPON 5 super_nailgun */
float(float action)
w_super_nailgun = {
if (action == WEAPON_AMMO) {
self.items |= IT_NAILS;
return self.ammo_nails;
} else if (action == WEAPON_WEIGHT) {
return 45;
} else if (action == WEAPON_SELECTABLE) {
if (!equip_query(self, EQUIPID_SUPER_NAILGUN))
return 0;
if (self.ammo_nails >= 2)
return 1;
return -1;
} else if (action == WEAPON_SELECT) {
self.weaponmodel = "progs/v_nail2.mdl";
self.weaponframe = 0;
self.mdl_mod = (self.mdl_mod & ~MDL_MOD_WEP_MASK) + MDL_MOD_WEP_SUPER_NAILGUN;
weaponprint(STR_EQUIPID_SUPER_NAILGUN);
} else if (action == WEAPON_FIRE) {
self.mdl_func(MDL_FUNC_FIRE, 0);
self.w_think = _w_super_nailgun_think;
self.w_think();
self.w_thought = TRUE;
} else if (action == WEAPON_INIT) {
precache_model("progs/v_nail2.mdl");
precache_model("progs/s_spike.mdl");
precache_sound("weapons/spike2.wav");
}
return 0;
};

View file

@ -0,0 +1,125 @@
#include "common.qh"
#include "weapon.qh"
#include "equip.qh"
#include "damage.qh"
#include "misc.qh"
#include "effect.qh"
#define STR_EQUIPID_ROCKET_LAUNCHER "Rocket Launcher"
void() _deathmsg_rocket_launcher = {
local string def_nname, att_nname;
local float r;
def_nname = name(self);
att_nname = name(self.dmg_attacker);
if (self == self.dmg_attacker) {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " uses his melee rocket launcher.\n");
else bprint(PRINT_DEATH, def_nname, " doesn't know how to use a rocket launcher.\n");
} else {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " rides ", att_nname, "'s rocket.\n");
else bprint(PRINT_DEATH, att_nname, "'s rocket got friendly with ", def_nname, ".\n");
}
};
void() _rocket_touch =
{
local float damg, contents;
contents = pointcontents(self.origin);
if (contents == CONTENT_SKY) {
remove(self);
return;
}
if (contents >= CONTENT_LAVA && contents <= CONTENT_WATER) {
self.dmg *= 0.9;
self.lip *= 0.8;
self.mass *= 1.5;
self.speed *= 0.8;
}
damg = self.dmg - 0.2*random()*self.dmg;
damage(other, self.goalentity, self, damg, _deathmsg_rocket_launcher);
self.velocity = '0 0 0';
damage_radius(other, self.goalentity, self, _deathmsg_rocket_launcher);
effect_explosion(self.origin);
safe_remove(self);
};
void() _w_rocket_launcher_think = {
self.weaponframe++;
if (self.weaponframe < 1 || self.weaponframe > 6) {
self.w_think = NOTHING_function;
self.weaponframe = 0;
}
};
void() _w_rocket_launcher_fire = {
local vector dir;
local entity missile;
if (!util_weapon_use_ammo(ammo_rockets, 1))
return;
sound(self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
makevectors(self.v_angle);
dir = aim(self, 1000);
missile = spawn_missile("ROCKET", "progs/missile.mdl", shootorigin(self), dir, 1000);
missile.dmg = 120;
missile.mass = missile.dmg * 8;
missile.lip = missile.dmg;
missile.touch = _rocket_touch;
damage_attack(missile);
self.weaponframe = 1;
self.w_think = _w_rocket_launcher_think;
self.mdl_func(MDL_FUNC_FIRE, 0);
effect_smallkick(self);
self.attack_finished = time + 0.8;
};
/* WEAPON 7 rocket_launcher */
float(float action)
w_rocket_launcher = {
if (action == WEAPON_AMMO) {
self.items |= IT_ROCKETS;
return self.ammo_rockets;
} else if (action == WEAPON_WEIGHT) {
return 55;
} else if (action == WEAPON_SELECTABLE) {
if (!equip_query(self, EQUIPID_ROCKET_LAUNCHER))
return 0;
if (self.ammo_rockets >= 1)
return 1;
return -1;
} else if (action == WEAPON_SELECT) {
self.weaponmodel = "progs/v_rock2.mdl";
self.weaponframe = 0;
self.mdl_mod = (self.mdl_mod & ~MDL_MOD_WEP_MASK) | MDL_MOD_WEP_ROCKET_LAUNCHER;
weaponprint(STR_EQUIPID_ROCKET_LAUNCHER);
} else if (action == WEAPON_FIRE) {
_w_rocket_launcher_fire();
} else if (action == WEAPON_INIT) {
precache_model("progs/v_rock2.mdl");
precache_model("progs/missile.mdl");
precache_sound("weapons/sgun1.wav");
}
return 0;
};

265
klik/weapons/w_shotgun.qc Normal file
View file

@ -0,0 +1,265 @@
#include "common.qh"
#include "weapon.qh"
#include "equip.qh"
#include "damage.qh"
#include "effect.qh"
#define STR_EQUIPID_SHOTGUN "Shotgun"
#define PUFF_RADIUS 60 /* FIXME: Base on spread too! */
void() _deathmsg_shotgun = {
local string def_nname, att_nname;
local float r;
def_nname = name(self);
att_nname = name(self.dmg_attacker);
if (self.dmg_attacker == self) {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " eats lead.\n");
else bprint(PRINT_DEATH, def_nname, " can't aim a shotgun.\n");
} else {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " eats a load of ", att_nname, "'s buckshot.\n");
else bprint(PRINT_DEATH, att_nname, " fills ", def_nname, " full of lead.\n");
}
};
void() _deathmsg_super_shotgun = {
local float r;
local string def_nname, att_nname;
def_nname = name(self);
att_nname = name(self.dmg_attacker);
if (self.dmg_attacker == self) {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " gets 2 shells.\n");
else bprint(PRINT_DEATH, def_nname, " practices hunting with a teleporter.\n");
} else {
r = random()*2;
if (r < 1) bprint(PRINT_DEATH, def_nname, " eats two loads of ", att_nname, "'s buckshot.\n");
else bprint(PRINT_DEATH, att_nname, " makes ", def_nname, " radiation resistant.\n");
}
};
entity(vector org, vector dir, entity ent) spawn_puff_damage = {
local entity inflictor;
inflictor = world;
while ((inflictor = find(inflictor, classname, "PUFF"))) {
if (vlen(inflictor.origin - org) > PUFF_RADIUS)
continue;
if (inflictor.enemy == ent)
break;
}
if (!inflictor) {
inflictor = spawn("PUFF");
inflictor.solid = SOLID_BBOX;
inflictor.movetype = MOVETYPE_FLY;
inflictor.deadflag = DEAD_NONLIVING;
inflictor.velocity = dir;
inflictor.angles = vectoangles(dir);
inflictor.owner = ent;
inflictor.enemy = ent;
inflictor.origin = org; // Don't bother linking.
}
inflictor.count++;
return inflictor;
};
void(float shotcount, vector spread, void() deathmessage) _fire_bullets =
{
local vector dir, direction;
local vector src;
local entity ignore, puff;
local float t_dmg, t_mass;
local float dist_left;
makevectors(self.v_angle);
dir = aim(self, 10000);
src = shootorigin(self);
/* See what a single missile would take.. */
ghost_inflictor.classname = "BULLET";
ghost_inflictor.velocity = dir*10000;
ghost_inflictor.dmg = 4;
ghost_inflictor.mass = ghost_inflictor.dmg;
damage_attack(ghost_inflictor);
t_dmg = ghost_inflictor.dmg;
t_mass = ghost_inflictor.mass;
/* Create the puff damage entities */
tl_proj_begin();
ignore = self;
dist_left = 8192;
do {
/* FIXME: Remove '0' when compiler is fixed */
for (0; shotcount > 0; shotcount--) {
direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
traceline(src, src + direction*dist_left, FALSE, ignore);
puff = spawn_puff_damage(trace_endpos, dir, trace_ent);
puff.health = dist_left;
}
puff = world;
while ((puff = find(puff, classname, "PUFF"))) {
tl_touch(puff.enemy, puff);
if (!tl_issolid(puff.enemy)) {
dist_left = puff.health - (dist_left*trace_fraction);
if (dist_left > 100)
break;
} else {
puff.dmg = t_dmg * puff.count;
puff.mass = t_mass * puff.mass;
if (!damage(puff.enemy, self, puff, puff.dmg, deathmessage))
effect_gun_spark(puff.origin, puff.velocity, puff.count);
}
puff.classname = "REMOVED_PUFF";
safe_remove(puff);
}
if (!puff)
break;
src = puff.origin;
ignore = puff.enemy;
shotcount = puff.count;
makevectors(puff.angles);
dir = v_forward;
remove(puff);
} while (1);
tl_proj_end();
};
void() _w_shotgun_think = {
self.weaponframe++;
if (self.weaponframe < 1 || self.weaponframe > 6) {
self.w_think = NOTHING_function;
self.weaponframe = 0;
}
};
void() _w_shotgun_fire =
{
if (!util_weapon_use_ammo(ammo_shells, 1))
return;
sound(self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);
_fire_bullets(6, '0.04 0.04 0', _deathmsg_shotgun);
self.weaponframe = 1;
self.w_think = _w_shotgun_think;
self.mdl_func(MDL_FUNC_FIRE, 0);
effect_smallkick(self);
self.attack_finished = time + 0.5;
};
/* WEAPON 2 shotgun */
float(float action)
w_shotgun = {
if (action == WEAPON_AMMO) {
self.items |= IT_SHELLS;
return self.ammo_shells;
} else if (action == WEAPON_WEIGHT) {
return 20;
} else if (action == WEAPON_SELECTABLE) {
if (!equip_query(self, EQUIPID_SHOTGUN))
return 0;
if (self.ammo_shells >= 1)
return 1;
return -1;
} else if (action == WEAPON_SELECT) {
self.weaponmodel = "progs/v_shot.mdl";
self.weaponframe = 0;
self.mdl_mod = (self.mdl_mod & ~MDL_MOD_WEP_MASK) | MDL_MOD_WEP_SHOTGUN;
weaponprint(STR_EQUIPID_SHOTGUN);
} else if (action == WEAPON_FIRE) {
_w_shotgun_fire();
} else if (action == WEAPON_INIT) {
precache_model("progs/v_shot.mdl");
precache_sound("weapons/guncock.wav");
}
return 0;
};
// ================================================================
#define STR_EQUIPID_SUPER_SHOTGUN "Super Shotgun"
void() _w_super_shotgun_fire =
{
if (self.ammo_shells == 1) {
_w_shotgun_fire();
return;
}
if (!util_weapon_use_ammo(ammo_shells, 2))
return;
sound(self, CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);
_fire_bullets(14, '0.14 0.08 0', _deathmsg_super_shotgun);
self.weaponframe = 1;
self.w_think = _w_shotgun_think;
self.mdl_func(MDL_FUNC_FIRE, 0);
effect_smallkick(self);
self.attack_finished = time + 0.7;
};
/* WEAPON 3 super_shotgun */
float(float action)
w_super_shotgun = {
if (action == WEAPON_AMMO) {
self.items |= IT_SHELLS;
return self.ammo_shells;
} else if (action == WEAPON_WEIGHT) {
return 40;
} else if (action == WEAPON_SELECTABLE) {
if (!equip_query(self, EQUIPID_SUPER_SHOTGUN))
return 0;
if (self.ammo_shells >= 2)
return 1;
return -1;
} else if (action == WEAPON_SELECT) {
self.weaponmodel = "progs/v_shot2.mdl";
self.weaponframe = 0;
self.mdl_mod = (self.mdl_mod & ~MDL_MOD_WEP_MASK) | MDL_MOD_WEP_SUPER_SHOTGUN;
weaponprint(STR_EQUIPID_SUPER_SHOTGUN);
} else if (action == WEAPON_FIRE) {
_w_super_shotgun_fire();
} else if (action == WEAPON_INIT) {
precache_model("progs/v_shot2.mdl");
precache_sound("weapons/shotgn2.wav");
}
return 0;
};

21
klik/weapons/w_void.qc Normal file
View file

@ -0,0 +1,21 @@
#include "common.qh"
#include "weapon.qh"
/* WEAPON 0 void */
float(float action)
w_void = {
if (action == WEAPON_AMMO) {
return 0;
} else if (action == WEAPON_WEIGHT) {
return -10000;
} else if (action == WEAPON_SELECTABLE) {
return 1;
} else if (action == WEAPON_SELECT) {
self.weaponmodel = "";
self.weaponframe = 0;
self.mdl_mod &= ~MDL_MOD_WEP_MASK;
}
/* FIRE and INIT don't do a darn thing */
return 0;
};

196
klik/weapons/weapon.qc Normal file
View file

@ -0,0 +1,196 @@
#include "common.qh"
#include "weapon.qh"
.float weapon_imp;
.float weapons; /* Alas, a bitfield. */
void() weapon_init = {
weapon_init_weapons();
};
void() weapon_player_init = {
self.weapons = 0;
self.weapon_imp = 0;
weapon_select_by_impulse(0);
};
float(float ex) exp2 = {
local float n;
n = 1;
if (ex >= 0) {
while (ex-- > 0)
n *= 2;
} else {
while (ex++ < 0)
n *= 0.5;
}
return n;
};
float() weapon_player_parm1 = {
local float parm, ex;
/* upper 19 bits of mantissa is self.weapons & 0x007fffe0 */
/* sign is self.weapons & 0x00800000 */
/* 8 bits of exponent is signed self.weapons & 0x1f */
/* lower 4 bits of mantissa is (self.weapon_imp << 1) + 1 */
parm = self.weapons & 8388576; /* 0x007fffe0 */
parm |= self.weapon_imp*2 + 1;
ex = floor(self.weapons & 31); /* 0x1f */
if (ex >= 16) ex -= 16;
parm *= exp2(ex);
if (parm & 8388608) /* 0x800000 */
parm = -parm;
return parm;
};
float() weapon_player_parm1_default = {
return 1; /* weapons 0x000000 weapon_imp 0 */
};
void(float parm) weapon_player_parm1_decode = {
local float ex, imp, topbit;
if (parm < 0) {
topbit = 8388608; /* 0x800000 */
parm = -parm;
} else {
topbit = 0;
}
/* Hooo boy. This is the slow way. */
ex = 0;
if (floor(parm) != parm) {
/* Negative exponent */
while (floor(parm) != parm) {
parm *= 2;
ex--;
}
ex += 8;
} else {
local float nparm;
/* Positive exponent */
nparm = parm * 0.5;
while (floor(nparm) == nparm) {
parm = nparm;
nparm *= 0.5;
ex++;
if (ex == 127)
break;
}
}
self.weapons = topbit | (parm & 8388576) | ex; /* 0x007fffe0 */
imp = floor((parm & 31) * 0.5); /* 0x1f */
weapon_select_by_impulse(imp);
if (!self.weapon_imp)
weapon_select_best();
};
void() _weapon_fire = {
if (!self.weapon_imp)
return;
if (self.w_func(WEAPON_SELECTABLE) <= 0) {
weapon_select_best();
if (self.w_func(WEAPON_SELECTABLE) <= 0)
return;
}
self.w_func(WEAPON_FIRE);
};
void() weapon_player_impulse = {
if (self.attack_finished >= time)
return;
if (self.impulse >= 1 && self.impulse <= 8) {
weapon_select_by_impulse(self.impulse);
self.impulse = 0;
}
if (self.button0)
_weapon_fire();
};
float(float imp) util_impulse_to_IT = {
if (imp == 1)
return IT_AXE;
else if (imp == 2)
return IT_SHOTGUN;
else if (imp == 3)
return IT_SUPER_SHOTGUN;
else if (imp == 4)
return IT_NAILGUN;
else if (imp == 5)
return IT_SUPER_NAILGUN;
else if (imp == 6)
return IT_GRENADE_LAUNCHER;
else if (imp == 7)
return IT_ROCKET_LAUNCHER;
else if (imp == 8)
return IT_LIGHTNING;
return 0;
};
void() weapon_set_ammo = {
self.items &= ~(IT_SHELLS|IT_NAILS|IT_ROCKETS|IT_CELLS);
if (!self.w_func)
self.currentammo = 0;
else
self.currentammo = self.w_func(WEAPON_AMMO);
};
void(float imp, float idx, float(float action) func) _weapon_select = {
local float bits, bitmask;
self.weapon_imp = imp;
bits = imp*3;
bitmask = 7*bits;
bitmask = -bitmask - 1;
self.weapons &= bitmask;
self.weapons |= idx*bits;
self.weapon = util_impulse_to_IT(imp);
self.w_think = NOTHING_function;
self.w_func = func;
self.w_func(WEAPON_SELECT);
};
void(string s) weaponprint = {
if (is_cl(self))
centerprint(self, "\[ ", s, " \]\n");
};
float(.float ammo_field, float ammo) util_weapon_use_ammo = {
if (self.ammo_field < ammo)
return FALSE;
self.ammo_field -= ammo;
return TRUE;
};
float(.float ammo_field, float max_ammo, float ammo) util_weapon_give_ammo = {
local float ret;
if (max_ammo > 999) max_ammo = 999;
ret = increase_field(ammo_field, ammo, max_ammo);
return ret;
};

37
klik/weapons/weapon.qh Normal file
View file

@ -0,0 +1,37 @@
#ifndef WEAPON_qh
#define WEAPON_qh 1
#include "weapon_g.qh"
#include "mdl.qh"
.float(float action) w_func;
.float attack_finished;
#define WEAPON_INIT 0
#define WEAPON_AMMO 1
#define WEAPON_WEIGHT 2
#define WEAPON_SELECTABLE 3
#define WEAPON_SELECT 4
#define WEAPON_FIRE 5
void() weapon_init;
void() weapon_player_init;
float() weapon_player_parm1;
void(float parm) weapon_player_parm1_decode;
float() weapon_player_parm1_default;
void() weapon_select_best;
void(float imp) weapon_select_by_impulse;
void() weapon_set_ammo;
void(string s) weaponprint;
void() weapon_player_impulse;
float(float impluse) util_impulse_to_IT;
float(.float ammo_field, float ammo) util_weapon_use_ammo;
float(.float ammo_field, float max_ammo, float ammo) util_weapon_give_ammo;
#endif

11
klik/weapons/weapon_g.qh Normal file
View file

@ -0,0 +1,11 @@
#ifndef WEAPON_G_qh
#define WEAPON_G_qh 1
void() weapon_init_weapons;
void() weapon_select_best;
void(float imp) weapon_select_by_impulse;
void() update_weapon_flags;
#endif

192
klik/weapons/weapon_gen.sh Executable file
View file

@ -0,0 +1,192 @@
#!/bin/bash
unset WEAPONS
unset ITFLAGS
ITFLAGS[1]="IT_AXE"
ITFLAGS[2]="IT_SHOTGUN"
ITFLAGS[3]="IT_SUPER_SHOTGUN"
ITFLAGS[4]="IT_NAILGUN"
ITFLAGS[5]="IT_SUPER_NAILGUN"
ITFLAGS[6]="IT_GRENADE_LAUNCHER"
ITFLAGS[7]="IT_ROCKET_LAUNCHER"
ITFLAGS[8]="IT_LIGHTNING"
IFS='
'
OFS='
'
cat << EOF
/* This file was automatically generated by $0 */
#include "common.qh"
#include "weapon.qh"
EOF
#################################################
for i in "$@"; do
for i in `grep '^/\* WEAPON ' "$i"`; do
unset IMPULSE NAME
IMPULSE=`echo "$i" | sed -e 's/^\/\* WEAPON \([0-9]\+\) \(.*\) \*\/$/\1/'`
NAME=`echo "$i" | sed -e 's/^\/\* WEAPON \([0-9]\+\) \(.*\) \*\/$/\2/'`
WEAPONS[$IMPULSE]="${WEAPONS[$IMPULSE]} $NAME"
cat << EOF
float(float action) w_${NAME};
EOF
done
done
unset IFS
##############################################
cat <<EOF
void() weapon_init_weapons = {
EOF
for i in `seq 0 8`; do
for j in ${WEAPONS[$i]}; do
echo " w_${j}(WEAPON_INIT);"
done
done
cat <<EOF
};
EOF
##############################################
cat <<EOF
void() weapon_select_best = {
local float best_imp, best_idx, best_weight, wweight;
local float bits, bitmask;
local float(float action) best_func;
best_func = self.w_func;
best_imp = self.weapon_imp;
best_weight = 0;
bits = best_imp*3;
bitmask = 7*best_imp;
best_idx = (self.weapons & bitmask) / bits;
EOF
for i in `seq 0 8`; do
COUNT=0
for j in ${WEAPONS[$i]}; do
cat << EOF
if (w_$j(WEAPON_SELECTABLE) > 0) {
wweight = w_$j(WEAPON_WEIGHT);
if (wweight > best_weight) {
best_weight = wweight;
best_imp = $i;
best_idx = $COUNT;
best_func = w_$j;
}
}
EOF
COUNT=$((COUNT+1));
done
done
cat <<EOF
_weapon_select(best_imp, best_idx, best_func);
};
EOF
############################################
cat <<EOF
void(float imp) weapon_select_by_impulse = {
local float i, bits, bitmask;
if (imp == 0) { _weapon_select(imp, 0, w_void); return; }
bits = imp*3;
bitmask = 7*imp;
i = (self.weapons & bitmask) / bits;
EOF
FIRST=1
for i in `seq 1 8`; do
WEAPON_MAX=$((`echo "${WEAPONS[$i]}" | wc -w`-1))
if [ "$WEAPON_MAX" -eq "-1" ]; then continue; fi
if [ "$FIRST" -eq "1" ]; then
echo " if (imp == $i) {"
FIRST=0
else
echo " } else if (imp == $i) {"
fi
cat <<EOF
if (imp == self.weapon_imp) i++;
EOF
COUNT=0
for j in ${WEAPONS[$i]}; do
if [ "$COUNT" -eq "0" ]; then continue; fi
cat <<EOF
if (i == $COUNT && w_$j(WEAPON_SELECTABLE)) { _weapon_select(imp, i, w_$j); return; } i++;
EOF
COUNT=$((COUNT+1))
done
cat <<EOF
i = 0;
EOF
COUNT=0
for j in ${WEAPONS[$i]}; do
cat <<EOF
if (i == $COUNT && w_$j(WEAPON_SELECTABLE)) { _weapon_select(imp, i, w_$j); return; } i++;
EOF
COUNT=$((COUNT+1))
done
done
cat <<EOF
}
};
EOF
#######################################################
cat <<EOF
void() update_weapon_flags = {
EOF
for i in `seq 1 8`; do
WEAPON_MAX=$((`echo "${WEAPONS[$i]}" | wc -w`-1))
cat <<EOF
self.items &= ~${ITFLAGS[$i]};
EOF
if [ "$WEAPON_MAX" -eq "-1" ]; then continue; fi
COUNT=0
for j in ${WEAPONS[$i]}; do
cat <<EOF
if (w_$j(WEAPON_SELECTABLE)) self.items |= ${ITFLAGS[$i]};
EOF
COUNT=$((COUNT+1))
done
echo
done
cat <<EOF
};
EOF

57
klik/worldspawn.qc Normal file
View file

@ -0,0 +1,57 @@
#include "common.qh"
void() worldspawn = {
/* These are used be the server C code, but not precached. Bad iD. */
precache_sound("misc/h2ohit1.wav");
precache_sound("demon/dland2.wav");
precache_sound("misc/r_tele1.wav");
precache_sound("misc/r_tele2.wav");
precache_sound("misc/r_tele3.wav");
precache_sound("misc/r_tele4.wav");
precache_sound("misc/r_tele5.wav");
/* Compatibility :) */
if (self.model == "maps/e1m8.bsp")
cvar_set("sv_gravity", "100");
// Setup light animation tables. 'a' is total darkness, 'z' is maxbright.
// 0 normal
lightstyle(0, "m");
// 1 FLICKER (first variety)
lightstyle(1, "mmnmmommommnonmmonqnmmo");
// 2 SLOW STRONG PULSE
lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
// 3 CANDLE (first variety)
lightstyle(3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
// 4 FAST STROBE
lightstyle(4, "ma");
// 5 GENTLE PULSE 1
lightstyle(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj");
// 6 FLICKER (second variety)
lightstyle(6, "nmonqnmomnmomomno");
// 7 CANDLE (second variety)
lightstyle(7, "mmmaaaabcdefgmmmmaaaammmaamm");
// 8 CANDLE (third variety)
lightstyle(8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
// 9 SLOW STROBE (fourth variety)
lightstyle(9, "aaaaaaaazzzzzzzz");
// 10 FLUORESCENT FLICKER
lightstyle(10, "mmamammmmammamamaaamammma");
// 11 SLOW PULSE NOT FADE TO BLACK
lightstyle(11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
// styles 32-62 are assigned by the light program for switchable lights
main();
};