mirror of
https://git.code.sf.net/p/quake/game-source
synced 2024-11-25 13:21:30 +00:00
<zinx> taniwha: FWIW, the code is officially donated to quakeforge :)
<taniwha> zinx: thanks :) zinx' klik mod :)
This commit is contained in:
parent
0e88e9927a
commit
88c055ea3c
99 changed files with 10309 additions and 0 deletions
120
klik/Makefile
Normal file
120
klik/Makefile
Normal 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
139
klik/Makefile.deps
Normal 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
13
klik/TODO
Normal 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
52
klik/act/act.qc
Normal 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
17
klik/act/act.qh
Normal 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
115
klik/act/act_dead.qc
Normal 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
10
klik/act/act_dead.qh
Normal 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
671
klik/act/act_player.qc
Normal 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
11
klik/act/act_player.qh
Normal 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
135
klik/bodyque.qc
Normal 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
11
klik/bodyque.qh
Normal 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
6
klik/builtins.qh
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef BUILTINS_qh
|
||||
#define BUILTINS_qh 1
|
||||
|
||||
#include SYSTEM_DIR "builtins.qh"
|
||||
|
||||
#endif
|
230
klik/client.qc
Normal file
230
klik/client.qc
Normal 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
16
klik/client.qh
Normal 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
10
klik/common.qh
Normal 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
37
klik/config.qh
Normal 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
218
klik/damage.qc
Normal 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
56
klik/damage.qh
Normal 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
13
klik/debug.qc
Normal 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
10
klik/debug.qh
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef DEBUG_qh
|
||||
#define DEBUG_qh 1
|
||||
|
||||
@extern {
|
||||
|
||||
void() debug_impulse;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
159
klik/defs.qh
Normal file
159
klik/defs.qh
Normal 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
111
klik/delays.qc
Normal 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
17
klik/delays.qh
Normal 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
17
klik/effect.qh
Normal 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
103
klik/entnum.qc
Normal 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
13
klik/entnum.qh
Normal 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
74
klik/equip.qc
Normal 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
31
klik/equip.qh
Normal 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
37
klik/equipid_gen.pl
Executable 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
520
klik/mapents/id_compat.qc
Normal 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
67
klik/mapents/items.qc
Normal 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
10
klik/mapents/items.qh
Normal 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
273
klik/mapents/mapents.qc
Normal 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();
|
||||
};
|
64
klik/mapents/mapents_items.qc
Normal file
64
klik/mapents/mapents_items.qc
Normal 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();
|
||||
};
|
||||
|
7
klik/mapents/mapents_items.qh
Normal file
7
klik/mapents/mapents_items.qh
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef MAPENTS_ITEMS_qh
|
||||
#define MAPENTS_ITEMS_qh 1
|
||||
|
||||
void() item_armor;
|
||||
void() item_ammo;
|
||||
|
||||
#endif
|
925
klik/mapents/mapents_movewall.qc
Normal file
925
klik/mapents/mapents_movewall.qc
Normal 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;
|
||||
};
|
6
klik/mapents/mapents_movewall.qh
Normal file
6
klik/mapents/mapents_movewall.qh
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef MAPENTS_MOVEWALL_qh
|
||||
#define MAPENTS_MOVEWALL_qh 1
|
||||
|
||||
void() func_train;
|
||||
|
||||
#endif
|
544
klik/mapents/mapents_powerup.qc
Normal file
544
klik/mapents/mapents_powerup.qc
Normal 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();
|
||||
};
|
14
klik/mapents/mapents_powerup.qh
Normal file
14
klik/mapents/mapents_powerup.qh
Normal 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
|
119
klik/mapents/mapents_traps.qc
Normal file
119
klik/mapents/mapents_traps.qc
Normal 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();
|
||||
};
|
258
klik/mapents/mapents_triggers.qc
Normal file
258
klik/mapents/mapents_triggers.qc
Normal 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;
|
||||
};
|
7
klik/mapents/mapents_triggers.qh
Normal file
7
klik/mapents/mapents_triggers.qh
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef MAPENTS_TRIGGERS_qh
|
||||
#define MAPENTS_TRIGGERS_qh 1
|
||||
|
||||
#define SPAWNFLAGS_TRIGGER_NOTOUCH 2
|
||||
void() trigger_generic;
|
||||
|
||||
#endif
|
182
klik/mapents/mapents_util.qc
Normal file
182
klik/mapents/mapents_util.qc
Normal 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;
|
||||
};
|
24
klik/mapents/mapents_util.qh
Normal file
24
klik/mapents/mapents_util.qh
Normal 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
20
klik/math.qc
Normal 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
14
klik/math.qh
Normal 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
25
klik/mdl/mdl.qc
Normal 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
36
klik/mdl/mdl.qh
Normal 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
18
klik/mdl/mdl_eyes.qc
Normal 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
7
klik/mdl/mdl_eyes.qh
Normal 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
396
klik/mdl/mdl_player.qc
Normal 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
7
klik/mdl/mdl_player.qh
Normal 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
13
klik/mdl/mdl_void.qc
Normal 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
6
klik/mdl/mdl_void.qh
Normal 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
17
klik/menu.qc
Normal 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
13
klik/menu.qh
Normal 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
53
klik/menus.qc
Normal 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
6
klik/menus.qh
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef MENUS_qh
|
||||
#define MENUS_qh 1
|
||||
|
||||
void() menu_intro;
|
||||
|
||||
#endif
|
402
klik/misc.qc
Normal file
402
klik/misc.qc
Normal 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
73
klik/misc.qh
Normal 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
176
klik/override.qc
Normal 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
49
klik/override.qh
Normal 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
140
klik/progdefs.h
Normal 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
46
klik/progs.src
Normal 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
6
klik/protocol.qh
Normal 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
96
klik/qw/builtins.qc
Normal 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
10
klik/qw/builtins.qh
Normal 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
96
klik/qw/effect.qc
Normal 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
40
klik/qw/protocol.qh
Normal 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
207
klik/qw/system.qc
Normal 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
8
klik/qw/system.qh
Normal 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
135
klik/qw/sz_watch.qc
Normal 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
12
klik/qw/sz_watch.qh
Normal 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
2
klik/regex
Executable 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
5
klik/regex.txt
Normal 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
111
klik/server.qc
Normal 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
27
klik/server.qh
Normal 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
16
klik/spectate.qc
Normal 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
84
klik/system.qc
Normal 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
8
klik/system.qh
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef SYSTEM_qh
|
||||
#define SYSTEM_qh 1
|
||||
|
||||
@extern {
|
||||
#include "system.qc"
|
||||
};
|
||||
|
||||
#endif
|
91
klik/teleport.qc
Normal file
91
klik/teleport.qc
Normal 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
12
klik/teleport.qh
Normal 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
|
64
klik/unused/item_menus.mnu
Normal file
64
klik/unused/item_menus.mnu
Normal 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
414
klik/unused/menusmarf.l
Normal 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
145
klik/unused/menusmarf.y
Normal 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
162
klik/unused/physics.qc
Normal 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
2
klik/unused/physics.qh
Normal file
|
@ -0,0 +1,2 @@
|
|||
void() physics_touch_bounce;
|
||||
void() physics_think_float;
|
105
klik/weapons/w_axe.qc
Normal file
105
klik/weapons/w_axe.qc
Normal 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;
|
||||
};
|
143
klik/weapons/w_grenade_launcher.qc
Normal file
143
klik/weapons/w_grenade_launcher.qc
Normal 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;
|
||||
};
|
228
klik/weapons/w_lightning_gun.qc
Normal file
228
klik/weapons/w_lightning_gun.qc
Normal 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
187
klik/weapons/w_nailgun.qc
Normal 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;
|
||||
};
|
125
klik/weapons/w_rocket_launcher.qc
Normal file
125
klik/weapons/w_rocket_launcher.qc
Normal 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
265
klik/weapons/w_shotgun.qc
Normal 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
21
klik/weapons/w_void.qc
Normal 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
196
klik/weapons/weapon.qc
Normal 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
37
klik/weapons/weapon.qh
Normal 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
11
klik/weapons/weapon_g.qh
Normal 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
192
klik/weapons/weapon_gen.sh
Executable 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
57
klik/worldspawn.qc
Normal 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();
|
||||
};
|
Loading…
Reference in a new issue